日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ThreadLocal原理

發布時間:2024/9/30 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ThreadLocal原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、定義

當需要為每一個線程設置一個私有的變量,進行線程隔離時,java提供的ThreadLocal可以幫助我們實現,ThreadLocal有一個內部ThreadLocalMap,存儲每個ThreadLocal對象和它的值,value為該線程獨有的數據,可以為多種類型

ThreadLocal、ThreadLocalMap、Thread三者之間的關系

1、ThreadLocal是一個本地線程副本變量工具類,主要用于將私有線程和該線程存放的副本對象做一個映射,各個線程之間的變量互不干擾,線程之間數據隔離,可通過set、get方法操作當前線程副本數據
2、ThreadLocalMap類是ThreadLocal的靜態內部類,通過操作Entry來存儲Thread和它對應的數據。
3、Thread類比較常用,線程類內部維持一個ThreadLocalMap類實例(threadLocals)

ThreadLocalMap是Thread的成員變量,又是ThreadLocal的靜態內部類,線程數據通過ThreadLocal來操控

二、使用方式

直接創建ThreadLocal對象,定義保存的數據類型,通過set方法設置值,get方法來取出

ThreadLocal<String> t=new ThreadLocal<>(); t.set("hello"); System.out.println(t.get());

注意:

1.這里只能set一次,再次在該線程set時會失效,只保留最新的值

2.ThreadLocal類中的ThreadLocalMap實體Entry繼承自WeakReference,是虛引用對象,只要發生垃圾回收GC,就會被回收掉ThreadLocalMap保存的value值

三、源碼解析

1.set方法

實際是獲取到當前的線程Thread和ThreadLocalMap對象,沒有則創建該map

public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value); }

map.set方法,獲取當前對象的的索引,通過線性探測法來放入對象,有沖突,往Entry數組下一個坐標位置移動

private void set(ThreadLocal<?> key, Object value) {// We don't use a fast path as with get() because it is at// least as common to use set() to create new entries as// it is to replace existing ones, in which case, a fast// path would fail more often than not.Entry[] tab = table;int len = tab.length;int i = key.threadLocalHashCode & (len-1);for (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {ThreadLocal<?> k = e.get();if (k == key) {e.value = value;return;}if (k == null) {replaceStaleEntry(key, value, i);return;}}tab[i] = new Entry(key, value);int sz = ++size;if (!cleanSomeSlots(i, sz) && sz >= threshold)rehash(); }

2.createMap方法

創建ThreadLocalMap,并賦值給當前的thread的成員變量

1)創建了一個Entry數組,大小為16,且該數組是繼承自WeakReference,表明在gc時會被回收掉

?table = new Entry[INITIAL_CAPACITY];static class Entry extends WeakReference<ThreadLocal<?>> {/** The value associated with this ThreadLocal. */Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;} }

2)計算散列索引位置并放入Entry數組

int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);table[i] = new Entry(firstKey, firstValue);private final int threadLocalHashCode = nextHashCode();private static final int HASH_INCREMENT = 0x61c88647;private static int nextHashCode() {return nextHashCode.getAndAdd(HASH_INCREMENT);}

與HashMap一樣,進行散列時,通過hashCode值和&運算來計算當前線程threadLocal的在threadLocalMap中的位置,每個ThreadLocal對象都共享同一個nextHashCode,每個ThreadLocal的HashCode值都會在當前值上加上一個16進制數0x61c88647,保證**實現了不同的ThreadLocal對象的threadLocalHashCode基本不會相同**

&屬于位運算,為了將該threadLocal盡量充分均勻的散列到Entry數組中,且計算更高效

解決Entry數組沖突的方法時開放定址法的線性探測法,每次加上一個數,再取余,有沖突

3)設置擴容因子

setThreshold(INITIAL_CAPACITY);private void setThreshold(int len) {threshold = len * 2 / 3; }

3.get方法

獲取ThreadLocalMap中當前線程對象對應的value值

public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}return setInitialValue(); }

如果ThreadLocalMap為null,則創建map,并設置當前線程key在ThreadLocalMap的value為null

private T setInitialValue() {T value = initialValue();Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);return value; }

4.remove方法

從ThreadLocalMap中移除當前線程對象和它持有value

public void remove() {ThreadLocalMap m = getMap(Thread.currentThread());if (m != null)m.remove(this); }

5.createInheritedMap方法

static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {return new ThreadLocalMap(parentMap); }

該方法是在Thread中調用的,Thread類中維護了一個ThreadLocalMap成員變量,用于初始化該mapi

f (parent.inheritableThreadLocals != null)this.inheritableThreadLocals =ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);

主要是通過當前線程thread獲取ThreadLocalMap對象,初始化數組和負載因子threshold,遍歷節點加入數組。

private ThreadLocalMap(ThreadLocalMap parentMap) {Entry[] parentTable = parentMap.table;int len = parentTable.length;setThreshold(len);table = new Entry[len];for (int j = 0; j < len; j++) {Entry e = parentTable[j];if (e != null) {@SuppressWarnings("unchecked")ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();if (key != null) {Object value = key.childValue(e.value);Entry c = new Entry(key, value);int h = key.threadLocalHashCode & (len - 1);while (table[h] != null)h = nextIndex(h, len);table[h] = c;size++;}}} }

?

?

?

?

?

?

?

?

?

?

?

?

?

總結

以上是生活随笔為你收集整理的ThreadLocal原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。