1. 程式人生 > >ThreadLocal原始碼解析,以及ThreadLocal、ThreadLocalMap、Thread 三者之間的關係

ThreadLocal原始碼解析,以及ThreadLocal、ThreadLocalMap、Thread 三者之間的關係

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

ThreadLocalMap 是 ThreadLocal 的內部類,Thread 中有個 ThreadLocalMap 成員變數 threadLocals 


ThreadLocal原始碼解析

下面看一下,jdk 關於 ThreadLocal api

ThreadLocal類 get 方法原始碼

public Object get()
    {
        Thread thread = Thread.currentThread();
        ThreadLocalMap threadlocalmap = getMap(thread);
        if(threadlocalmap != null)
        {
            ThreadLocalMap.Entry entry = threadlocalmap.getEntry(this);
            if(entry != null)
                return entry.value;
        }
        return setInitialValue();
    }

private Object setInitialValue()
    {
        Object obj = initialValue();
        Thread thread = Thread.currentThread();
        ThreadLocalMap threadlocalmap = getMap(thread);
        if(threadlocalmap != null)
            threadlocalmap.set(this, obj);
        else
            createMap(thread, obj);
        return obj;
    }

protected Object initialValue()
    {
        return null;
    }
當get一個值時,
獲取當前執行緒,呼叫 getMap 方法獲取當前執行緒的 ThreadLocalMap,如果獲取的 ThreadLocalMap != null 那麼就將 ThreadLocalMap 中儲存的 value 返回給呼叫者。如果獲取的 ThreadLocalMap == null 那麼呼叫 setInitialValue 方法,setInitialValue方法中呼叫了 initialValue 方法,並將 initialValue 方法的返回值 obj 儲存到 ThreadLocalMap 中,然後將 返回值 obj 返回給呼叫者。

ThreadLocal類 set 方法原始碼

public void set(Object obj)
    {
        Thread thread = Thread.currentThread();
        ThreadLocalMap threadlocalmap = getMap(thread);
        if(threadlocalmap != null)
            threadlocalmap.set(this, obj);
        else
            createMap(thread, obj);
    }

ThreadLocalMap getMap(Thread thread)
    {
        return thread.threadLocals;
    }

void createMap(Thread thread, Object obj)
    {
        thread.threadLocals = new ThreadLocalMap(this, obj);
    }

當set一個值時,獲取當前執行緒,呼叫 getMap 方法獲取當前執行緒的 ThreadLocalMap,如果獲取的 ThreadLocalMap == null 那麼呼叫 createMap 方法建立一個ThreadLocalMap,並將 obj 放入到 ThreadLocalMap 中。(注意:ThreadLocalMap 中 key 是 ThreadLocal,value 是 傳入的 obj引數。 為什麼ThreadLocalMap 中 key 是 ThreadLocal,因為一個執行緒可以有多個 ThreadLocal )

ThreadLocal類 remove 方法原始碼

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

刪除當前 ThrealLocal 對應的 value

例項程式碼

public static void main(String[] args) {
		ThreadLocal<String> tl = new ThreadLocal<String>();
		String str = tl.get();
		System.out.println("輸出字串:" + str);
	}
輸出結果
輸出字串:null

public static void main(String[] args) {
	ThreadLocal<String> tl = new ThreadLocal<String>(){
		@Override
		protected String initialValue() {
			return "lp";
		}
	};
	String str = tl.get();
	System.out.println("輸出字串:" + str);
}

輸出結果
輸出字串:lp

至於為什麼輸出結果 不一樣,我想打架看了上面的原始碼解析應該都明白了吧。

如果不想重寫 ThreadLocal 中的 initialValue 方法 也可以先呼叫 set 方法 再 呼叫 get 方法,就像下面這樣

public static void main(String[] args) {
	ThreadLocal<String> tl = new ThreadLocal<String>();
	tl.set("lp");
	String str = tl.get();
	System.out.println("輸出字串:" + str);
}

輸出結果
輸出字串:lp


補充

ThreadLocal 的執行緒安全性稍差的堂兄弟,InheritableThreadLocal

ThreadLocal 類有一個親戚,InheritableThreadLocal,它以相似的方式工作,但適用於種類完全不同的應用程式。建立一個執行緒時如果儲存了所有 InheritableThreadLocal 物件的值,那麼這些值也將自動傳遞給子執行緒。如果一個子執行緒呼叫 InheritableThreadLocal 的 get() ,那麼它將與它的父執行緒看到同一個物件。為保護執行緒安全性,您應該只對不可變物件(一旦建立,其狀態就永遠不會被改變的物件)使用InheritableThreadLocal ,因為物件被多個執行緒共享。 InheritableThreadLocal 很合適用於把資料從父執行緒傳到子執行緒,例如使用者標識(user id)或事務標識(transaction id),但不能是有狀態物件,例如 JDBC Connection 。


相關推薦

ThreadLocal原始碼解析以及ThreadLocalThreadLocalMapThread 三者之間關係

ThreadLocal、ThreadLocalMap、Thread 三者之間的關係 ThreadLocalMap 是 ThreadLocal 的內部類,Thread 中有個 ThreadLocalM

ThreadLocal原始碼解析記憶體洩露以及傳遞性

我想ThreadLocal這東西,大家或多或少都瞭解過一點,我在接觸ThreadLocal的時候,覺得這東西很神奇,在網上看了很多部落格,也看了一些書,總覺得有一個坎跨不過去,所以對ThreadLocal一直是一知半解的,好在這東西在實際開發中畢竟用的不多,所以也就得過且過了。當然我說的“用的不多”,只是對於

Java ThreadLocal原始碼解析: ThreadLocalMap

ThreadLocalMap在比其中Thread和ThreadLocal部分要複雜很多,是ThreadLocal底層儲存和核心資料結構。從整體上將,ThreadLocalMap底層是Entry陣列,key值為ThreadLocal的hash code, 採用線性探測法解決雜湊衝突。 以下

Java ThreadLocal原始碼解析: ThreadThreadLocal

之前對TreadLocal有所理解,對原理也有所瞭解,但一直不深入,重新整理,希望藉以加深理解和印象。 在Jdk1.8中,ThreadLocal相關程式碼主要分為三部分: Thread,其中Thread中儲存對ThreadLocal.ThreadLocalMap的引用,作為T

併發程式設計---ThreadLocal原始碼解析

    在遇到執行緒安全問題的時候,我們一般都是使用同步來解決,比如內建鎖、顯示鎖等等。執行緒安全的主要起因是因為多個執行緒同時操作一個共享變數,如果我們換種思路,在某些場景下,我們為這些執行緒提供共享變數的副本,讓他們在自己的私有域中去操作這些變數,執行緒之間互不影響,那是不是

Java 8 ThreadLocal 原始碼解析

Java 中的 ThreadLocal是執行緒內的區域性變數, 它為每個執行緒儲存變數的一個副本。ThreadLocal 物件可以在多個執行緒中共享, 但每個執行緒只能讀寫其中自己的副本。 目錄: 程式碼示例 原始碼解析 InheritableThreadLocal ThreadLoca

jscss 阻塞dom解析以及專案中遇到的一些問題

先上圖, 1, 不會阻塞 DOM 的解析,但會阻塞 DOM 渲染。 2,JS 阻塞 DOM 解析,但瀏覽器會"偷看"DOM,預先下載相關資源。 3,瀏覽器遇到 <script>且沒有 defer 或 async 屬性的 標籤時,會觸發頁面渲染,因而如果前面 C

Redis原始碼解析:25叢集(一)握手心跳訊息以及下線檢測

         Redis叢集是Redis提供的分散式資料庫方案,通過分片來進行資料共享,並提供複製和故障轉移功能。 一:初始化 1:資料結構 在原始碼中,通過server.cluster記錄整個叢集當前的狀態,比如叢集中的所有節點;叢集目前的狀態,比如是上線還是下線;

詳解Java中的ThreadLocalThreadLocalMapThread之間關係

每個ThreadLocal例項都有一個唯一的threadLocalHashCode(這個值將會用於在ThreadLocalMap中找到ThreadLocal對應的value值),它是通過靜態變數nextHashCode和HASH_INCREMENT進行計算的,其中nextH

ThreadLocal 原始碼解析和使用

ThreadLocal定義 ThreadLocal是Java語言提供用於支援執行緒區域性變數的類。 ThreadLocal不是為了解決多執行緒訪問共享變數,而是通過為每個執行緒提供一個獨立的變數副本來解決變數併發訪問的衝突問題。 ThreadLocal

Java8 ThreadLocal 原始碼解析

前言 ThreadLocal ,像是一個神祕的黑衣人,令人望而生畏。唯有下定決心,一探究竟,方能解開他神祕的面紗、在Android中,Handler,EventBus,ConnectionPool 等等,都曾出現它的身影 是什麼東西? 看到Thread

ThreadLocal原始碼解析

 ThreadLocal不是一個具體的執行緒。它是一個執行緒內部的資料儲存類,通過它可以再指定的執行緒中儲存資料,資料儲存以後,只有在指定執行緒中可以獲取到儲存的資料,對於其它執行緒來說則無法獲取到資料

ThreadLocal 原始碼解析

引言 ThreadLocal 可以在每個執行緒中存取資料,並且不同的執行緒中的資料互不影響。使用在資料以執行緒為作用域並且不同的執行緒擁有不用的資料副本,或者是複雜的引數傳遞時(引數在同一執行緒中的不同類中傳遞)。 在分析訊息機制原始碼的時候,涉及到了 Th

曹工說Redis原始碼(5)-- redis server 啟動過程解析以及EventLoop每次處理事件前的前置工作解析(下)

文章導航 Redis原始碼系列的初衷,是幫助我們更好地理解Redis,更懂Redis,而怎麼才能懂,光看是不夠的,建議跟著下面的這一篇,把環境搭建起來,後續可以自己閱讀原始碼,或者跟著我這邊一起閱讀。由於我用c也是好幾年以前了,些許錯誤在所難免,希望讀者能不吝指出。 曹工說Redis原始碼(1)-- redi

ThreadLocal原始碼解析-Java8

目錄 一.ThreadLocal介紹   1.1 ThreadLocal的功能   1.2 ThreadLocal使用示例 二.原始碼分析-ThreadLocal   2.1 ThreadLocal的類層級關係   2.2 ThreadLocal的屬性欄位   2.3 建立ThreadLocal物件

任務和目標的區別以及怎樣完成任務實現目標

獲得 可能性 都是 一個 結合 意誌力 試驗 專家 www https://www.douban.com/note/524880185/?type=like 使用Todoist工作了一段時間,完成了一些工作,也造成了一些拖延。造成拖延的原因是,我實在是沒有辦法在設定的dea

[python] 連接MySQL以及多線程多進程連接MySQL續

python mysqldb dbutils pooleddb之前參照他人的做法,使用DBUtils.PooledDB來建立多個可復用的MySQL連接,部分文章有誤,方法不當,導致我走了很多彎路,專研幾天後,終於找到了正確的使用方法。網上有很多使用DBUtils.PooledDB模塊建立連接池,再加threa

java 集合類 底層原始碼解析慢速更新~偏新手

我決定從java底層原始碼開始自己的部落格之旅,水平有限,很有可能寫的不對,歡迎大家指出缺點~部落格慢速保持更新! 先從java最常用的集合類開始更新吧~ java的集合類均來自於 java.util包下 java單列頂層介面 Collection 先看看該介面的定義: pub

Tomcat原始碼解析:Jsp檔案的編譯實現

1.Jsp簡介     jsp(java server page),其根本是一個簡化的Servlet技術,是一種動態網頁技術標準。     它是在傳統的網頁HTML頁面中插入java程式碼段,從而形成jsp檔案,字尾為.jsp。  

關於ThreadLocal的實現原理以及ThreadLocal為什麼會造成記憶體洩露

用處 可以私有化儲存執行緒的變數值 用法 static class ResourceClass { public final static ThreadLocal<String> RESOURCE_1 =