最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java線程變量ThreadLocal源碼分析

 更新時(shí)間:2022年08月26日 11:41:35   作者:niuyongzhi  
ThreadLocal用來(lái)提供線程內(nèi)部的局部變量,不同的線程之間不會(huì)相互干擾,這種變量在多線程環(huán)境下訪問(wèn)時(shí)能保證各個(gè)線程的變量相對(duì)獨(dú)立于其他線程內(nèi)的變量,在線程的生命周期內(nèi)起作用,可以減少同一個(gè)線程內(nèi)多個(gè)函數(shù)或組件之間一些公共變量傳遞的復(fù)雜度

1.ThreadLocal 線程變量,和當(dāng)前線程綁定的,只保存當(dāng)前線程的變量,對(duì)于其他線程是隔離的,是訪問(wèn)不到里面的數(shù)據(jù)的。

2.在Looper中使用到了ThreadLocal,創(chuàng)建了一個(gè)Looper是保存到了ThreadLocal中。

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

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

先拿到當(dāng)前線程,然后在拿到該線程的ThreadLocalMap成員變量,然后保存到這個(gè)map中,

key就是創(chuàng)建的ThreadLocal對(duì)象,value就是傳進(jìn)來(lái)的value。

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

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

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

2)保存數(shù)據(jù),如果map為空的情況。則創(chuàng)建ThreadLocalMap,并賦值給當(dāng)前線程t。

 void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}
 ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
    //創(chuàng)建一個(gè)大小為16的數(shù)組
    table = new Entry[INITIAL_CAPACITY];
    //計(jì)算得到的i是數(shù)組的角標(biāo)??梢詤⒖糷ashMap源碼分析
    int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
    //賦值,保存數(shù)據(jù)
    table[i] = new Entry(firstKey, firstValue);
    size = 1;
    //擴(kuò)容的閾值
    setThreshold(INITIAL_CAPACITY);
}

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

也是先拿到當(dāng)前線程t,然后通過(guò)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對(duì)應(yīng)的索引
    int i = key.threadLocalHashCode & (table.length - 1);
    //從數(shù)組中拿到Entry
    Entry e = table[i];
    if (e != null && e.get() == key){如果key一樣直接返回
        return e;
    }else{//如果不一致則開(kāi)始遍歷
         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時(shí),得到的map是空的,則這個(gè)時(shí)候需要初始化

//如果map為空,則調(diào)用這個(gè)方法,initialValue由用戶去實(shí)現(xiàn)。
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;
    }
};

總結(jié)ThreadLocal是通過(guò) ThreadLocalMap 進(jìn)行數(shù)據(jù)的存儲(chǔ)的。而這個(gè)ThreadLocalMap對(duì)象是通過(guò)

獲取到當(dāng)前線程,并從當(dāng)前線程中拿到的。所以ThreadLocalMap只保存本線程的數(shù)據(jù),做到了線程隔離。

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

如果想要給ThreadLocalMap中存更多的數(shù)據(jù),則需要?jiǎng)?chuàng)建多個(gè)對(duì)象。

到此這篇關(guān)于Java線程變量ThreadLocal源碼分析的文章就介紹到這了,更多相關(guān)Java ThreadLocal內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • spring boot添加新模塊的方法教程

    spring boot添加新模塊的方法教程

    這篇文章主要給大家介紹了關(guān)于spring boot添加新模塊的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • 全方位解析key值不確定的json數(shù)據(jù)

    全方位解析key值不確定的json數(shù)據(jù)

    這篇文章主要介紹了全方位解析key值不確定的json數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-01-01
  • Kotlin 與 Java基本語(yǔ)法對(duì)比

    Kotlin 與 Java基本語(yǔ)法對(duì)比

    這篇文章主要介紹了Kotlin 與 Java基本語(yǔ)法對(duì)比的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • Springboot整合freemarker和相應(yīng)的語(yǔ)法詳解

    Springboot整合freemarker和相應(yīng)的語(yǔ)法詳解

    FreeMarker是一款Spring官方推薦使用的模板引擎。接下來(lái)通過(guò)本文給大家介紹Springboot整合freemarker和相應(yīng)的語(yǔ)法,感興趣的朋友一起看看吧
    2021-09-09
  • 詳解maven BUILD FAILURE的解決辦法

    詳解maven BUILD FAILURE的解決辦法

    這篇文章主要介紹了詳解maven BUILD FAILURE的解決辦法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • 使用JPA自定義SQL查詢結(jié)果

    使用JPA自定義SQL查詢結(jié)果

    這篇文章主要介紹了使用JPA自定義SQL查詢結(jié)果,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Spring IOC源碼剖析_如何整體認(rèn)知Spring體系結(jié)構(gòu)

    Spring IOC源碼剖析_如何整體認(rèn)知Spring體系結(jié)構(gòu)

    這篇文章主要介紹了Spring IOC源碼剖析_如何整體認(rèn)知Spring體系結(jié)構(gòu)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java檢查字符串是否一致的四種方法

    Java檢查字符串是否一致的四種方法

    字符串比較是常見(jiàn)的操作,包括比較相等、比較大小、比較前綴和后綴串等,在 Java 中,比較字符串的常用方法有四個(gè):equals(),equalsIgnoreCase(),compareTo()和compareToIgnoreCase(),下面詳細(xì)介紹這四個(gè)方法的使用
    2024-04-04
  • Java線程池復(fù)用線程的秘密你知道嗎

    Java線程池復(fù)用線程的秘密你知道嗎

    這篇文章主要為大家詳細(xì)介紹了Java線程池復(fù)用線程的秘密,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望您能夠多多關(guān)注

    2022-03-03
  • 關(guān)于Socket的解析以及雙方即時(shí)通訊的java實(shí)現(xiàn)方法

    關(guān)于Socket的解析以及雙方即時(shí)通訊的java實(shí)現(xiàn)方法

    本篇文章主要介紹了關(guān)于Socket的解析以及雙方通訊的java實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-03-03

最新評(píng)論

新宾| 玛纳斯县| 潢川县| 新邵县| 息烽县| 苗栗市| 全南县| 蛟河市| 浮山县| 林芝县| 荃湾区| 增城市| 霍林郭勒市| 洪雅县| 闸北区| 偃师市| 盱眙县| 寻乌县| 黄龙县| 保亭| 湟源县| 凤城市| 陕西省| 镇赉县| 南陵县| 金川县| 麻江县| 洛川县| 高邮市| 佳木斯市| 栾川县| 双鸭山市| 民和| 富顺县| 衡阳县| 贺兰县| 子长县| 凤凰县| 辽宁省| 新竹县| 日照市|