国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

ThreadLocal源碼分析

2019-11-15 01:03:43
字體:
來源:轉載
供稿:網友
ThreadLocal源碼分析

我們知道,進程是OS分配資源的最小單位,而線程是執(zhí)行操作的最小單位并不享有資源。ThreadLocal實現(xiàn)了線程數(shù)據(jù)變量的本地存儲,每個線程都存儲自己的變量,所有的線程都使用同樣的ThreadLocal<T>對象來存取變量,但是每個線程在存取時看到的變量值是不同的,不會影響到其他線程的變量,并且值可以為null。

整個實現(xiàn)架構圖如下:

image

一個線程可以持有多個ThreadLocal對象,每個ThreadLocal實例其實很輕量級,只保存hashCounter分配給它的hash值和自身的一個弱引用。存取時只要將values里的obj數(shù)組復制當前方法的局部變量中操作就可以了。

原來的JDK中,table是用map實現(xiàn)的;在1.7源碼中使用了object數(shù)組來存放<ThreadLocal,T>,如圖間隔存放了kv;這樣做避開了線程并發(fā)的鎖操作,大大加快了存取的速度。另外值得提一點的是,hashCounter每次分配給ThreadLocal對象的hash值都是偶數(shù),這樣取得的index位置來存放ThreadLocal對象,index+1位置存放變量值,十分巧妙。

ThreadLocal類結構如下,我們接下來依次分析這些方法:

image

  • Values 靜態(tài)內部類,相當于一個全局變量,里面維護了一個object數(shù)組,使每個線程都可以訪問它。
  • public ThreadLocal() {}構造方法為空
  • public T get() 返回了當前線程中存儲的變量值
  • PRotected T initialValue() 返回null,根據(jù)需要重寫該方法
  • public void set(T value) 設置當前線程中存儲的變量值
  • public void remove() 刪除當前線程中存儲的變量值
  • Values initializeValues(Thread current) 創(chuàng)建當前進程對應的values對象
  • Values values(Thread current) 獲取當前進程的values實例

介紹完了整個架構,我們先不去看values這個靜態(tài)內部類,其實它維護了ThreadLocal到變量值的映射,一個hashtable而已,回頭再來看它。

先來看一眼完成當前線程變量值的get方法:

public T get() {        // Optimized for the fast path.        Thread currentThread = Thread.currentThread();//獲取到當前線程實例        Values values = values(currentThread);//獲取到當前線程對應的values實例        if (values != null) {            Object[] table = values.table;            int index = hash & values.mask;            if (this.reference == table[index]) {                return (T) table[index + 1];            }        } else {            values = initializeValues(currentThread);//如果當前線程對應的values為空,就新建一個        }        return (T) values.getAfterMiss(this);    }

方法中,根據(jù)當前線程實例獲取到values,先來看看如果values為空會如何?

如果values為空則對其初始化,調用initializeValues方法:

/**     * Creates Values instance for this thread and variable type.     */    Values initializeValues(Thread current) {        return current.localValues = new Values();//new一個values實例    }

我們來看一下Values的構造方法:

Values() {            initializeTable(INITIAL_SIZE);//INITIAL_SIZE為16            this.size = 0;//table中存儲的鍵值對entry數(shù)目            this.tombstones = 0;//廢棄的entry數(shù)目        }

通過initializeTable方法來創(chuàng)建一個object數(shù)組,容量為32,mask值為0x1F。

private void initializeTable(int capacity) {            this.table = new Object[capacity * 2];//通過給定的初始化容量創(chuàng)建table,一個obj數(shù)組            this.mask = table.length - 1;//之前capacity規(guī)定必須為2的冪,這里length默認為31,            this.clean = 0;            this.maximumLoad = capacity * 2 / 3; // 2/3 最大負載因子        }

我們重新回到get方法中,方法最后返回getAfterMiss(this),該方法將當前ThreadLocal傳入,并返回initialValue()定義的值,這個方法是可以自定義重寫的。

如果values不為空,我們將副本table復制到當前方法變量中進行操作,由于每個ThreadLocal對象都有固定的hash值,所以不存在線程并發(fā)的問題。

ThreadLocal中其他的操作方法也是這樣。操作完成后,我們需要與Values中的數(shù)組交互,這里就調用了put方法:

/**         * Sets entry for given ThreadLocal to given value, creating an         * entry if necessary.         */        void put(ThreadLocal<?> key, Object value) {            cleanUp();//先清理了廢棄的元素            // Keep track of first tombstone. That's where we want to go back            // and add an entry if necessary.            int firstTombstone = -1;            for (int index = key.hash & mask;; index = next(index)) {                Object k = table[index];                if (k == key.reference) {                    // Replace existing entry.                    table[index + 1] = value;                    return;                }                if (k == null) {                    if (firstTombstone == -1) {                        // Fill in null slot.                        table[index] = key.reference;                        table[index + 1] = value;                        size++;                        return;                    }                    // Go back and replace first tombstone.                    table[firstTombstone] = key.reference;                    table[firstTombstone + 1] = value;                    tombstones--;                    size++;                    return;                }                // Remember first tombstone.                if (firstTombstone == -1 && k == TOMBSTONE) {                    firstTombstone = index;                }            }        }

每次操作object數(shù)組,都要先清理一下廢棄的元素。然后再進行元素存放。

總結

ThreadLocal與values的組合設計實現(xiàn)了多個線程存儲本地變量而又互不干擾的功能,更令人叫絕的是通過固定hash值分配的方式,避開了鎖操作。關于Values內部的object數(shù)組的維護比較復雜,以后有機會再來研究補充。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 岳池县| 广水市| 定襄县| 晋中市| 宾阳县| 叙永县| 界首市| 武安市| 丰县| 嘉祥县| 肥城市| 汕头市| 博罗县| 卓资县| 乌审旗| 高雄县| 怀远县| 白玉县| 丽江市| 枣庄市| 盱眙县| 和平县| 阜康市| 永顺县| 杨浦区| 富宁县| 龙井市| 黄龙县| 平湖市| 恩施市| 邵东县| 桐梓县| 望都县| 高尔夫| 湾仔区| 筠连县| 霍山县| 兴安县| 开鲁县| 菏泽市| 水城县|