Java高併發6-ThreadLocal內部各類方法實現原理

1、複習

  • 上下文切換的時機:(1)線程中斷的時候;(2)線程使用完時間片處於就緒狀態的時候
  • 造成死鎖的四個條件:(1)互斥條件;(2)請求並持有條件;(3)不可剝奪條件;(4)環路等待條件
  • 根據操做系統原理,目前只能破除(2)和(4)
  • 守護線程,格式:線程實例.setDaemon(true)
  • ThreadLocal每個線程都會copy一份

2、ThreadLocal實現原理

1.首先看一下Thread類

  • Thread類中有兩個成員變量
  • ThreadLocalMap threadLocals
  • ThreadLocalMap inheritableThreadLocals

2.而後再看一下TheadLocal類中的成員方法

  • void set(T value)
  • T get()
  • ThreadLocalMap getMap(Thread t)
  • void remove()
  • T setInitialValue()
  • void createMap(Thread t,T value)

3.ThreadLocalMap

  • 能夠理解爲這是一個定製的HashMap
  • 咱們看到Thread裏面的成員變量threadLocals,其實內部存儲的就是ThreadLocal的內容,ThreadLocal實際上是一個工具殼,也就是說爲何會在每個線程都有個ThreadLocal的副本,咱們就解釋通了,由於它是Thread的自有成員變量
  • 咱們看一下ThreadLocal中set()方法的實現
 ThreadLocalMap threadLocals;
 ThreadLocalMap inheritableThreadLocals;
  
 public void set(T value) {
  Thread t = Thread.currentThread();//首先獲取進程自己
  //首先獲取成員變量
  ThreadLocalMap map = get(t);
  if(map != null) {
   map.set(this,value);
  }else {
   createMap(t,value);
  }
  
  
 }
 
 ThreadLocalMap get(Thread t) {
  return t.threadLocals;
 }
 
 void createMap(Thread t,T value) {
  //key是this,這就說明,只能是這個ThreadLocal實例做爲惟一key,這也保證了,全部線程的本地
  //變量threadLocals的key是一致,保證了數據一致,若是用Thread實例作key,那就確定不同了,
  //由於每一個Thread的實例不同。
  threadLocals = new ThreadLocalMap(this,value);
 }
 
  • 總結:線程裏面放一個map,而後ThreadLocal實例作key,set()方法裏面放一個T value,那麼就能夠達到放副本了,用ThreadLocal實例作key,能夠保證不一樣線程用的value同樣。

4.get()方法

 public T get() {
  Thread t = Thread.currentThread();//和set方法同樣先獲取本線程 
  ThreadLocalMap map = getMap(t);
  if(map != null) {
   ThreadLocalMap.Entry e = map.getEntry(this);
   if(e!=null) {
    
    T result = (T)e.value();
    return result;
   }
  }
  return setInitialValue();
 }
 
 private T setInitialValue() {  
  T value = initialValue();
  
  //下面的代碼和set同樣,只不過咱們只是提早設置了null爲value
  Thread t = Thread.currentThread();
  ThreadLocalMap  map = getMap(t);
  if(map != null) {
   map.set(this,value);
  }else {
   createMap(t,value);
   
  }
  return value;
 }
 
 protected T initialValue() {
  return null;
 }
}

5. remove方法

 public void remove() {
  ThreadLocalMap m = getMap(Thread.currentThread());  
  if(m != null) {
   m.remove(this);
  }
 }
  • 總結:在每個線程內部都有一個ThreadLocal變量,該變量的類型是HashMap,其中key就是咱們的ThreadLocal實例,value就是調用set方法內部傳參的類型。每一個線程的本地變量都會存在本身的threadLocal中,若是當前線程一直不消亡,那麼這些變量就會一直存在,所以咱們應該使用完線程以後,及時調用remove,刪除這個多餘的變量。不然會形成內存溢出。

3、源碼:

相關文章
相關標籤/搜索