public class MyDemo {private static ThreadLocal<String> tl = new ThreadLocal<>();private String content;private String getContent() {return tl.get();}private void setContent(String content) {tl.set(content);}public static void main(String[] args) {MyDemo demo = new MyDemo();for (int i = 0; i < 5; i++) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {demo.setContent(Thread.currentThread().getName() + "的数据");System.out.println("-----------------------");System.out.println(Thread.currentThread().getName() + "--->" + demo.getContent());}});thread.setName("线程" + i);thread.start();}}}
打印结果:
?

文章插图
从结果来看 , 这样很好的解决了多线程之间数据隔离的问题 , 十分方便 。
1.3 ThreadLocal类与synchronized关键字1.3.1 synchronized同步方式? 这里可能有的朋友会觉得在上述例子中我们完全可以通过加锁来实现这个功能 。我们首先来看一下用synchronized代码块实现的效果:
public class Demo02 {private String content;public String getContent() {return content;}public void setContent(String content) {this.content = content;}public static void main(String[] args) {Demo02 demo02 = new Demo02();for (int i = 0; i < 5; i++) {Thread t = new Thread(){@Overridepublic void run() {synchronized (Demo02.class){demo02.setContent(Thread.currentThread().getName() + "的数据");System.out.println("-------------------------------------");String content = demo02.getContent();System.out.println(Thread.currentThread().getName() + "--->" + content);}}};t.setName("线程" + i);t.start();}}}
打印结果:?

文章插图
? 从结果可以发现, 加锁确实可以解决这个问题 , 但是在这里我们强调的是线程数据隔离的问题 , 并不是多线程共享数据的问题, 在这个案例中使用synchronized关键字是不合适的 。
1.3.2 ThreadLocal与synchronized的区别? 虽然ThreadLocal模式与synchronized关键字都用于处理多线程并发访问变量的问题, 不过两者处理问题的角度和思路不同 。
synchronizedThreadLocal原理同步机制采用'以时间换空间'的方式, 只提供了一份变量,让不同的线程排队访问ThreadLocal采用'以空间换时间'的方式, 为每一个线程都提供了一份变量的副本,从而实现同时访问而相不干扰侧重点多个线程之间访问资源的同步性多线程中让每个线程之间的数据相互隔离
总结: 在刚刚的案例中 , 虽然使用ThreadLocal和synchronized都能解决问题,但是使用ThreadLocal更为合适,因为这样可以使程序拥有更高的并发性 。
2. 运用场景_事务案例? 通过以上的介绍 , 我们已经基本了解ThreadLocal的特点 。但是它具体的应用是在哪里呢? 现在让我们一起来看一个ThreadLocal的经典运用场景: 事务 。2.1 转账案例2.1.1 场景构建? 这里我们先构建一个简单的转账场景: 有一个数据表account , 里面有两个用户Jack和Rose , 用户Jack给用户Rose 转账 。
? 案例的实现就简单的用mysql数据库 , JDBC 和 C3P0 框架实现 。以下是详细代码 :
? (1) 项目结构

文章插图
? (2) 数据准备
-- 使用数据库use test;-- 创建一张账户表create table account( id int primary key auto_increment, name varchar(20), money double);-- 初始化数据insert into account values(null, 'Jack', 1000);insert into account values(null, 'Rose', 1000);
【ThreadLocal的介绍与运用】? (3) C3P0配置文件和工具类<c3p0-config><!-- 使用默认的配置读取连接池对象 --><default-config> <!--连接参数 --> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property> <property name="user">root</property> <property name="password">1234</property> <!-- 连接池参数 --> <property name="initialPoolSize">5</property> <property name="maxPoolSize">10</property> <property name="checkoutTimeout">3000</property></default-config></c3p0-config>
经验总结扩展阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 为啥有的票直达还得换座
- 冰冻的火锅丸子煮多久
- 之八 2流高手速成记:基于Sentinel实现微服务体系下的限流与熔断
- 8k和a3纸的一样大么
- chrome工具调试
- 蓝色糖心玛瑙是天然的吗
- 马克笔和记号笔的区别
- 想开发DAYU200,我教你
- 火车z,k,c,t开头的代表什么?
- 1.5*1.8的床多大 1.5米的床用多大的床单