ThreadLocal的用法理解

  • 其实很简单,就是创建一个对象,然后每个线程去访问时,访问的是这个对象的副本。即该对象会为每个线程拷贝出一个副本。
  • 其实效果和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线程修改的值在主线程中可以看到。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容