91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java線程變量ThreadLocal源碼分析

發布時間:2022-08-26 14:04:15 來源:億速云 閱讀:153 作者:iii 欄目:開發技術

這篇文章主要介紹“Java線程變量ThreadLocal源碼分析”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“Java線程變量ThreadLocal源碼分析”文章能幫助大家解決問題。

1.ThreadLocal 線程變量,和當前線程綁定的,只保存當前線程的變量,對于其他線程是隔離的,是訪問不到里面的數據的。

2.在Looper中使用到了ThreadLocal,創建了一個Looper是保存到了ThreadLocal中。

//這里用到了泛型,ThreadLocal中只保存Looper對象。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) { //保證Looper只被創建一次。
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));
}

看下sThreadLocal.set()方法是如何保存數據的。

先拿到當前線程,然后在拿到該線程的ThreadLocalMap成員變量,然后保存到這個map中,

key就是創建的ThreadLocal對象,value就是傳進來的value。

  public void set(T value) {
        //拿到當前線程
        Thread t = Thread.currentThread();
        //得到一個map
        ThreadLocalMap map = getMap(t);
        if (map != null){
        // 這個map是以當前對象為key的,這個this就是 ThreadLocal的實例 sThreadLocal
            map.set(this, value);
        }else{
            createMap(t, value);
        }
    }
//getMap 是從Thread中拿到了一個threadLocals變量,是ThreadLocal.ThreadLocalMap 的實例。
//保存的數據也是存在了這個map中,這也就是為什么ThreadLocal是和線程綁定的,對其他線程來說是隔離的原因所在。
ThreadLocalMap getMap(Thread t) {
      return t.threadLocals;
}

1)保存數據,如果map不為空的情況。走上面if判斷的第一個分支。這個存儲方式和HashMap類似

private void set(ThreadLocal<?> key, Object value) {
      Entry[] tab = table;
      int len = tab.length;
      // 計算出key在集合中的索引,index
      int i = key.threadLocalHashCode & (len-1);
       //開始遍歷整個數組,
       //取出索引為i的Entry,如果不為空,取出下一個,進行遍歷
        for (Entry e = tab[i];
               e != null;
               e = tab[i = nextIndex(i, len)]) {
              ThreadLocal<?> k = e.get();
              //如果取出的k和傳進來的key一致,則把新的值存起來。
              if (k == key) {
                  e.value = value;
                  return;
              }
              //直到取出最有一個,k==null則進行存儲。
              if (k == null) {
                  replaceStaleEntry(key, value, i);
                  return;
              }
          }
          //如果索引i的位置,沒有Entry,則把傳進來的key和value保存在這個位置。
          tab[i] = new Entry(key, value);
          int sz = ++size;
          //如果大于閾值了,則進行擴容
          if (!cleanSomeSlots(i, sz) && sz >= threshold)
              rehash();
}

2)保存數據,如果map為空的情況。則創建ThreadLocalMap,并賦值給當前線程t。

 void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}
 ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
    //創建一個大小為16的數組
    table = new Entry[INITIAL_CAPACITY];
    //計算得到的i是數組的角標。可以參考hashMap源碼分析
    int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
    //賦值,保存數據
    table[i] = new Entry(firstKey, firstValue);
    size = 1;
    //擴容的閾值
    setThreshold(INITIAL_CAPACITY);
}

3.再看看ThreadLocal是如何取值的。

也是先拿到當前線程t,然后通過t拿到他的成員變量ThreadLocalMap。

public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    //如果map不為空,則從map中取值
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    //如果map為空
    return setInitialValue();
}

1)如果map不為空則從map中取值。

//如果map不為空
 private Entry getEntry(ThreadLocal<?> key) {
    //拿到key對應的索引
    int i = key.threadLocalHashCode & (table.length - 1);
    //從數組中拿到Entry
    Entry e = table[i];
    if (e != null && e.get() == key){如果key一樣直接返回
        return e;
    }else{//如果不一致則開始遍歷
         return getEntryAfterMiss(key, i, e);
    }
}
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
		Entry[] tab = table;
		int len = tab.length;
		while (e != null) {
			ThreadLocal<?> k = e.get();
			if (k == key)
				return e;
			if (k == null)
				expungeStaleEntry(i);
			else
				i = nextIndex(i, len);
			e = tab[i];
		}
		return null;
}

2)如果在get時,得到的map是空的,則這個時候需要初始化

//如果map為空,則調用這個方法,initialValue由用戶去實現。
private T setInitialValue() {
    T value = initialValue();
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
    return value;
}
//下面是Choreographer中的例子:
private static final ThreadLocal<Choreographer> sThreadInstance =
        new ThreadLocal<Choreographer>() {
    @Override
    protected Choreographer initialValue() {
        Looper looper = Looper.myLooper();
        if (looper == null) {
            throw new IllegalStateException("The current thread must have a looper!");
        }
        Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
        if (looper == Looper.getMainLooper()) {
            mMainInstance = choreographer;
        }
        return choreographer;
    }
};

總結ThreadLocal是通過 ThreadLocalMap 進行數據的存儲的。而這個ThreadLocalMap對象是通過

獲取到當前線程,并從當前線程中拿到的。所以ThreadLocalMap只保存本線程的數據,做到了線程隔離。

ThreadLocalMap存數據的key是ThreadLocal對象本身。 map.set(this, value);

如果想要給ThreadLocalMap中存更多的數據,則需要創建多個對象。

關于“Java線程變量ThreadLocal源碼分析”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

浦江县| 洞头县| 大邑县| 安康市| 北川| 九龙县| 石嘴山市| 大连市| 宜兰县| 汉中市| 南宁市| 江山市| 阿尔山市| 安西县| 吉首市| 盐城市| 高平市| 噶尔县| 新巴尔虎左旗| 苗栗市| 前郭尔| 齐河县| 腾冲县| 富锦市| 恩平市| 阳江市| 攀枝花市| 宜州市| 旺苍县| 南华县| 崇左市| 临安市| 左权县| 石家庄市| 富川| 广南县| 东山县| 灌南县| 仁布县| 陈巴尔虎旗| 吉木乃县|