第一、前言
建议将本文和ThreadLocal应用场景-事务案例一起阅读。
第二、ThreadLocal简介
从Java官方文档中的描述:ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的变量。ThreadLocal实例通常来说都是private static类型的,用于关联线程和线程上下文。
总结:
1.线程并发:在多线程并发的场景下
2.传递数据:我们可以通过ThreadLocal在同一线程,不同组件中传递公共变量
3.线程隔离:每个线程的变量都是独立的,不会相互影响
第三、使用案例
/**
* 验证线程数据隔离
* @author shixiancheng
* 2020-07-25
*/
public class Test {
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public static void main(String [] args){
final Test test=new Test();
//开启5个线程
for(int i=1;i<=5;i++){
Thread t=new Thread(){
@Override
public void run() {
//每个线程存一个变量,然后取出这个变量
test.setContent(Thread.currentThread().getName()+"的数据");
System.out.println("============================");
System.out.println(Thread.currentThread().getName()+":"+test.getContent());
}
};
t.setName("线程"+i);
t.start();
}
}
}
运行结果
============================
线程1:线程1的数据
============================
线程3:线程3的数据
============================
线程5:线程2的数据
============================
线程2:线程4的数据
============================
线程4:线程4的数据
从结果可以看出多个线程在访问同一个变量的时候出现的异常,线程间的数据没有隔离。下面我们来看下采用 ThreadLocal 的方式来解决这个问题的例子。
/**
* 验证线程数据隔离
* @author shixiancheng
* 2020-07-25
*/
public class Test {
private ThreadLocal<String> tl=new ThreadLocal<String>();
public String getContent() {
return tl.get();//取出当前线程绑定的变量
}
public void setContent(String content) {
tl.set(content);//将content绑定到当前线程
}
public static void main(String [] args){
final Test test=new Test();
//开启5个线程
for(int i=1;i<=5;i++){
Thread t=new Thread(){
@Override
public void run() {
//每个线程存一个变量,然后取出这个变量
test.setContent(Thread.currentThread().getName()+"的数据");
System.out.println("============================");
System.out.println(Thread.currentThread().getName()+":"+test.getContent());
}
};
t.setName("线程"+i);
t.start();
}
}
}
运行结果
============================
============================
线程4:线程4的数据
============================
线程2:线程2的数据
线程1:线程1的数据
============================
线程3:线程3的数据
============================
线程5:线程5的数据
从结果来看,这样很好的解决了多线程之间数据隔离的问题,十分方便。
其实加锁也可以实现线程安全
/**
* 验证线程数据隔离
* @author shixiancheng
* 2020-07-25
*/
public class Test {
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public static void main(String [] args){
final Test test=new Test();
//开启5个线程
for(int i=1;i<=5;i++){
Thread t=new Thread(){
@Override
public void run() {
synchronized(Test.class){
//每个线程存一个变量,然后取出这个变量
test.setContent(Thread.currentThread().getName()+"的数据");
System.out.println("============================");
System.out.println(Thread.currentThread().getName()+":"+test.getContent());
}
}
};
t.setName("线程"+i);
t.start();
}
}
}
运行结果
============================
线程1:线程1的数据
============================
线程3:线程3的数据
============================
线程4:线程4的数据
============================
线程2:线程2的数据
============================
线程5:线程5的数据
从结果可以发现, 加锁确实可以解决这个问题,但是在这里我们强调的是线程数据隔离的问题,并不是多线程共享数据的问题, 在这个案例中使用synchronized关键字是不合适的。
第四、ThreadLocal与synchronized的区别

第五、ThreadLocal方案的好处
从上述的案例中可以看到,在一些特定场景下,ThreadLocal方案有两个突出的优势:
1.传递数据:保存每个线程绑定的数据,在需要的地方可以直接获取,避免参数直接传递带来的代码耦合问题。
2.线程隔离:各线程之间的数据相互隔离却又具备并发性,避免同步方式带来的性能损失。
欢迎大家积极留言交流学习心得,点赞的人最美丽,谢谢