您的位置:首页 > 其它

ThreadLocal的用法理解

2018-01-08 16:46 393 查看
其实很简单,就是创建一个对象,然后每个线程去访问时,访问的是这个对象的副本。即该对象会为每个线程拷贝出一个副本。

其实效果和local variable是一个效果。即在线程内初始化一个本地变量。

ThreadLocal<String> threadLocalOld = new ThreadLocal<String>(){
@Override
protected String initialValue() {
return new String("dsadsa");
}
};
Thread thread = new Thread(()->{
String s = threadLocalOld.get();//每个线程调度get函数获取本线程的副本。
// do sth
threadLocalOld.set("dsad");// set函数set的值,只会设置本线程的值,不会对其他线程有任何影响。
});
Thread thread1 = new Thread(()->{
String s = new String("dsadsa");//ThreadLocal效果定义local variable类似。
// do sth
});


但ThreadLocal要比local variable优点:

1. 当我们需要给线程传递数据时,

如果这个数据是线程安全的(不可变的)或线程处理中是只读操作,那线程中直接使用即可。

如果这个数据是非线程安全的,则使用ThreadLocal是一个好的选择。相比在线程中定义一个这个数据的副本要好。因为ThreadLocal有更大的scope。

2. 线程内全局变量的效果。

我们在线程内可以通过set和get得到,即set的值可以在线程内anywhere通过get得到 。所以如果线程函数内有多层嵌套调用,则无需传递此值。其实相当于线程内的全局变量。

ThreadLocal的误用:

public static void main(String[] args){
TT tt = new TT("a", 1);
ThreadLocal<TT> ttThreadLocal = ThreadLocal.withInitial(()->tt);
Thread t1 = new Thread(()->{
ttThreadLocal.get().setS("b");
});
t1.start();
try {
t1.join();
System.out.println(JSON.toJSONString(tt));
} catch (Exception e) {
e.printStackTrace();
}
}


此时的输出是{“i”:1,”s”:”b”}。

即initialValue的误用。即ThreadLocal在线程调用的时候就会去调用initiaValue来得到本线程的副本,而如果用户自己写的initialValue函数并不是new一个对象,而是直接返回全局变量,则这里就会出错。即t1线程修改的值在主线程中可以看到。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息