Java執行緒上下文 ThreadLocal的那些事

2021-08-21 11:36:34 字數 3463 閱讀 1013

threadlocal:通常被稱作執行緒本地變數或者執行緒本地儲存。其含義是threadlocal為變數在每個執行緒中都建立乙個副本,則每個執行緒可以訪問自身內部的副本變數。

概念總是抽象而且晦澀的,我們從兩個例子說起。

如下圖,有個多層呼叫的情況,如果我們需要傳遞某個中間結果在這幾層呼叫關係之間,應該怎麼處理呢?

}如果需要將乙個單執行緒的應用移植到到多執行緒的環境下,就需要將共享的一些全域性變數轉換為threadlocal物件;這相當於threadlocal為每個執行緒都建立了乙個該全域性變數的副本。保證了其執行緒安全性。

但是,theadlocal並不是解決高併發下共享資源的方式。大多數情況下,threadlocal儲存的是乙個new的新物件。但是如果其儲存乙個物件的引用,也會面臨資源競爭的情況。

public

class threadlocaldemo );

}pool.shutdownnow();

system.out.println(a);}}

最終輸出a的值完全不固定。這是因為static a 為共享變數,每個執行緒(包括main執行緒)都儲存了乙個a的引用的副本。threadlocal並不能替代synchronized的作用。- 例子2:threadlocal儲存的是共享變數的引用

public

class threadlocaldemo catch (exception e) {}

}}).start();

timeunit.seconds.sleep(2);

student.name = "b"; // 修改共享變數

}private

static

class student

public string tostring() }}

執行2秒後,執行緒1的threadlocal會被main執行緒修改。則對共享變數的操作,同樣存在多執行緒的競爭情況。結論:threadlocal的使用通常由private static修飾,適用於物件/方法間跨層傳遞,或實現變數在多執行緒之間的隔離,並非解決多執行緒同步問題。常用於儲存session、db連線等。我們還是從下面的乙個例子說起,從執行結果看,每個執行緒均儲存了乙個執行緒副本,且相互之間互不影響。這是因為每個執行緒的副本中都存放的是乙個new變數,而並非共享變數。每個執行緒各自維護。

public

class threadlocalexample catch (exception e) {}

system.out.println(thread.currentthread().getname() + ":" + local.get());

});}}}

使用threadlocal,最常用的幾個方法,分別為initialvalue()set(t value)get()remove()

protected t initialvalue()
threadlocalmap getmap(thread t) 

public

void

set(t value)

void createmap(thread t, t firstvalue)

首先通過getmap(thread t)獲取當前執行緒所屬的threadlocalmap,然後將value設定到這個map中;如果當前執行緒沒有這個map,則新建乙個。

public t get() 

}return setinitialvalue();

}

上面所看到的threadlocalmap是乙個和hashmap差不多的結構,用來儲存執行緒放在threadlocal中的資料備份,其所有方法都為private。但實際上儲存資料的為下面的entry。

static class

entry

extends

weakreference

>>

}

entry為乙個弱引用型別,主要是使jvm能夠自動**。

同樣,我們首先看乙個例子。

public

class threadlocalmemory

}

通過jprofile檢視下記憶體和gc情況,發現在進行gc之後,記憶體並沒有減小:

我們可以分析下threadlocal 的set情況:

執行threadlocal = null;後,

雖然threadlocalmap中的enry為弱引用,為的就是當沒有強引用指向 threadlocal 變數時,它可被**,從而避免threadlocal 不能被**而造成的記憶體洩漏的問題。

但是,entry中value為乙個對值的強引用。當 threadlocal 變數被**後,該entry的key變為 null,該 entry 無法被移除致使記憶體洩漏。

那我們應該怎麼避免這種情況呢?答案就是在**threadlocal之前,先把其中的資料清理。如下:

程序上下文與執行緒上下文

6.1.2 執行緒上下文 作業系統管理很多程序的執行。有些程序是來自各種程式 系統和應用程式的單獨程序,而某些程序來自被分解為很多程序的應用或程式。當乙個程序從核心中移出,另乙個程序成為活動的,這些程序之間便發生了上下文切換。作業系統必須記錄重啟程序和啟動新程序使之活動所需要的所有資訊。這些資訊被稱...

上下文 上下文棧

全域性 函式 區域性 在執行全域性 前將window確定為全域性執行上下文 對全域性資料進行預處理 var定義的全域性變數 undefined,新增為window的屬性 function宣告的全域性函式 賦值 fun 新增為window的方法 this 賦值 window 開始執行全域性 在呼叫函式...

java多執行緒 上下文切換

併發程式設計的目的是為了讓程式執行得更快,但是並不是啟動更多的執行緒就能讓程式最大限度地併發執行。在進行併發程式設計時,如果希望通過多執行緒執行任務讓程式執行得更快,會面臨非常多的挑戰,比如上下文切換的問題 死鎖的問題,以及受限於硬體和軟體的資源限制問題,本文要研究的是上下文切換的問題。即使是單核c...