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線程修改的值在主線程中可以看到。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容