<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
最近在工作中結合執行緒池使用 InheritableThreadLocal
出現了獲取執行緒變數“錯誤”的問題,看了相關的檔案和原始碼後在此記錄。
InheritableThreadLocal
只有在父執行緒建立子執行緒時,在子執行緒中才能獲取到父執行緒中的執行緒變數;
當配合執行緒池使用時:“第一次線上程池中開啟執行緒,能在子執行緒中獲取到父執行緒的執行緒變數,而當該子執行緒開啟之後,發生執行緒複用,該子執行緒仍然保留的是之前開啟它的父執行緒的執行緒變數,而無法獲取當前父執行緒中新的執行緒變數”,所以會發生獲取執行緒變數錯誤的情況。
/** * 測試執行緒池下InheritableThreadLocal執行緒變數失效的場景 */ public class TestInheritableThreadLocal { private static final InheritableThreadLocal<String> threadLocal = new InheritableThreadLocal<>(); // 固定大小的執行緒池,保證執行緒複用 private static final ExecutorService executorService = Executors.newFixedThreadPool(1); public static void main(String[] args) { threadLocal.set("main執行緒 變數1"); // 正常取到 main執行緒 變數1 executorService.execute(() -> System.out.println(threadLocal.get())); threadLocal.set("main執行緒 變數2"); // 執行緒複用再取還是 main執行緒 變數1 executorService.execute(() -> System.out.println(threadLocal.get())); } }
輸出結果:
main執行緒 變數1 main執行緒 變數1
發現兩次輸出結果值相同,證明發生執行緒複用時,子執行緒獲取父執行緒變數失效
This class extends ThreadLocal to provide inheritance of values from parent thread to child thread: when a child thread is created, the child receives initial values for all inheritable thread-local variables for which the parent has values. Normally the child's values will be identical to the parent's; however, the child's value can be made an arbitrary function of the parent's by overriding the childValue method in this class. Inheritable thread-local variables are used in preference to ordinary thread-local variables when the per-thread-attribute being maintained in the variable (e.g., User ID, Transaction ID) must be automatically transmitted to any child threads that are created.
InheritableThreadLocal
繼承了 ThreadLocal
, 以能夠讓子執行緒能夠從父執行緒中繼承執行緒變數: 當一個子執行緒被建立
時,它會接收到父執行緒中所有可繼承的變數。通常情況下,子執行緒和父執行緒中的執行緒變數是完全相同的,但是可以通過重寫 childValue
方法來使父子執行緒中的值不同。
當執行緒中維護的變數如UserId, TransactionId 等必須自動傳遞到新建立的任何子執行緒時,使用InheritableThreadLocal
要優於ThreadLocal
public class InheritableThreadLocal<T> extends ThreadLocal<T> { /** * 當子執行緒被建立時,通過該方法來初始化子執行緒中執行緒變數的值, * 這個方法在父執行緒中被呼叫,並且在子執行緒開啟之前。 * * 通過重寫這個方法可以改變從父執行緒中繼承過來的值。 * * @param parentValue the parent thread's value * @return the child thread's initial value */ protected T childValue(T parentValue) { return parentValue; } ThreadLocalMap getMap(Thread t) { return t.inheritableThreadLocals; } void createMap(Thread t, T firstValue) { t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue); } }
其中childValue
方法來獲取父執行緒中的執行緒變數的值,也可通過重寫這個方法來將獲取到的執行緒變數的值進行修改。
在getMap
方法和createMap
方法中,可以發現inheritableThreadLocals
變數,它是 ThreadLocalMap
,在Thread類
中
public Thread(ThreadGroup group, String name) { init(group, null, name, 0); }
init
方法的最終實現,其中有如下邏輯:為當前執行緒建立執行緒變數以繼承父執行緒中的執行緒變數/** * @param inheritThreadLocals 為ture,代表是為 包含可繼承的執行緒變數 的執行緒進行初始化 */ private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals) { ... if (inheritThreadLocals && parent.inheritableThreadLocals != null) // 注意這裡建立子執行緒的執行緒變數 this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); ... }
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals)
建立子執行緒 InheritedMap
的具體實現
createInheritedMap
方法,最終會呼叫到 ThreadLocalMap
的私有構造方法,傳入的引數parentMap即為父執行緒中儲存的執行緒變數
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) { // 注意!!! 這裡呼叫了childValue方法 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++; } } } }
這個方法會對父執行緒中的執行緒變數做深拷貝,其中呼叫了childValue
方法來獲取/初始化子執行緒中的值,並儲存到子執行緒中
InheritableThreadLocal
的 createMap
方法,建立 inheritableThreadLocals
並儲存執行緒變數以上就是java開發工作中對InheritableThreadLocal使用思考的詳細內容,更多關於java開發InheritableThreadLocal的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45