Java并發(fā)編程之threadLocal
1、ThreadLocal介紹
多個(gè)線程訪問同一個(gè)共享變量時(shí)特別容易出現(xiàn)并發(fā)問題,特別是多線程需要對(duì)共享變量進(jìn)行寫入時(shí)。為了保證線程安全,一般使用者在訪問共享變量的時(shí)候需要進(jìn)行適當(dāng)?shù)耐?,如圖

同步的一般措施是加鎖,這就需要使用者對(duì)鎖有一定的了解,這顯然加重了使用者的負(fù)擔(dān),那么有沒有一種方法可以做到,當(dāng)創(chuàng)建一個(gè)變量后,每個(gè)線程對(duì)其進(jìn)行訪問的時(shí)候訪問的是自己線程的變量呢?其實(shí)ThreadLocal就可以做到。
ThreadLocal是JDK包提供的,它提供了線程本地變量,也就是說如果創(chuàng)建了一個(gè)ThreadLocal變量,那么訪問這個(gè)變量的每一個(gè)線程都會(huì)有這個(gè)變量的一個(gè)本地副本。當(dāng)多線程操作這個(gè)變量的時(shí)候,實(shí)際操作的就是自己本地內(nèi)存的里面的里面的變量,從而避免了線程安全問題。創(chuàng)建一個(gè)ThreadLocal變量后,每一個(gè)線程都會(huì)復(fù)制一個(gè)變量到自己的本地內(nèi)存。

2、ThreadLocal使用實(shí)例
package com.heiye.learn1;
public class ThreadLocalTest {
//print方法
static void print(String threadName) {
//打印當(dāng)前線程本地內(nèi)存中LocalVariable變量的值
System.out.println(threadName + ":" + localVariable.get());
//清除當(dāng)前線程本地內(nèi)存中的localVariable變量值
//localVariable.remove();
}
//創(chuàng)建ThreadLocal變量
static ThreadLocal<String> localVariable = new ThreadLocal<>();
public static void main(String[] args) {
//創(chuàng)建線程threadOne
Thread threadOne = new Thread(new Runnable() {
@Override
public void run() {
//設(shè)置線程one變量localVariable值
localVariable.set("threadOne local Variable");
//調(diào)用打印函數(shù)
print("threadOne");
//打印本地變量值
System.out.println("threadOne remove after" + ":" + localVariable.get());
}
});
//創(chuàng)建線程threadTwo
Thread threadTwo = new Thread(new Runnable() {
@Override
public void run() {
//設(shè)置線程two變量localVariable值
localVariable.set("threadTwo local Variable");
//調(diào)用打印函數(shù)
print("threadTwo");
//打印本地變量值
System.out.println("threadTwo remove after" + ":" + localVariable.get());
}
});
threadOne.start();
threadTwo.start();
}
}

線程one首先通過set()方法為threadLocal變量設(shè)置了一個(gè)值,這其實(shí)設(shè)置的就是線程one本地內(nèi)存中對(duì)于threadLocal變量的一個(gè)副本。這個(gè)副本是線程two訪問不了的。
如果清除當(dāng)前線程本地內(nèi)存中的localVariable變量值,也就是執(zhí)行localVariable.remove() ;則:

3、ThreadLocal實(shí)現(xiàn)原理
首先查看一下ThreadLocal類圖結(jié)構(gòu)

由該圖可知,Thread類有一個(gè)ThreadLocals和inheritableThreadLocals,它們都是ThreadLocalMap類型的變量,而ThreadLocalMap是一個(gè)定制化的HashMap。在默認(rèn)的情況下,每個(gè)線程中的兩個(gè)變量都為null,只有當(dāng)?shù)谝粋€(gè)線程調(diào)用ThreadLocal的set或者get方法時(shí)才會(huì)創(chuàng)建它們,其實(shí)每個(gè)線程得到本地變量不是存放在ThreadLocal實(shí)例里面,而是存放在具體的線程內(nèi)存空間里。ThreadLocal就是一個(gè)工具殼,它通過set方法把value值存放在調(diào)用線程的threadlocals里面并存放起來,當(dāng)調(diào)用線程調(diào)用它的get()方法的時(shí)候,再從當(dāng)前線程的threadLocals變量里面將其拿出來使用。
分析set,get,remove邏輯
//set
public void set(T value) {
//獲取當(dāng)前線程
Thread t = Thread.currentThread();
//將當(dāng)前線程作為key,到ThreadLocalMap取查找對(duì)應(yīng)的線程變量
ThreadLocalMap map = getMap(t);
//如果找到,則設(shè)置
if (map != null)
map.set(this, value);
else //第一次調(diào)用就創(chuàng)建當(dāng)前線程所在的hashmap
createMap(t, value);
}
//get
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();
}
//remove
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
在每一個(gè)線程內(nèi)都有一個(gè)名為threadLocals的成員變量,該變量的類型為HashMap,其中的key為我們定義的threadLocal變量的this引用,value為我們使用set方法設(shè)置的值。每個(gè)線程的本地變量存放在自己的內(nèi)存變量ThreadLocals中,如果當(dāng)前線程一直不消亡,那么這些本地變量會(huì)一直存在,所有可能造成內(nèi)存溢出。
到此這篇關(guān)于Java并發(fā)編程 threadLocal 的文章就介紹到這了,更多相關(guān)threadLocal 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java多維數(shù)組和Arrays類方法總結(jié)詳解
這篇文章主要介紹了Java多維數(shù)組和Arrays類方法總結(jié)詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03
SpringBoot項(xiàng)目配置明文密碼泄露問題的處理方式
這篇文章主要介紹了SpringBoot項(xiàng)目配置明文密碼泄露問題的處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
Springboot實(shí)現(xiàn)Java阿里短信發(fā)送代碼實(shí)例
這篇文章主要介紹了springboot實(shí)現(xiàn)Java阿里短信發(fā)送代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02
Java中雙重檢查鎖(double checked locking)的正確實(shí)現(xiàn)
雙重檢查鎖(Double-Check Locking),顧名思義,通過兩次檢查,并基于加鎖機(jī)制,實(shí)現(xiàn)某個(gè)功能,下面這篇文章主要給大家介紹了關(guān)于Java中雙重檢查鎖(double checked locking)的相關(guān)資料,需要的朋友可以參考下2021-09-09
Java阻塞延遲隊(duì)列DelayQueue原理及使用詳解
這篇文章主要介紹了Java阻塞延遲隊(duì)列DelayQueue原理及使用詳解,阻塞隊(duì)列是一個(gè)支持兩個(gè)附加操作的隊(duì)列,這兩個(gè)附加的操作是:在隊(duì)列為空時(shí),從隊(duì)列中獲取元素的消費(fèi)者線程會(huì)一直等待直到隊(duì)列變?yōu)榉强?需要的朋友可以參考下2023-12-12
IntelliJ IDEA彈出“IntelliJ IDEA License Activation”的處理方法
這篇文章主要介紹了IntelliJ IDEA彈出“IntelliJ IDEA License Activation”的處理方法,本文給出解決方法,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
java語言基礎(chǔ)之標(biāo)識(shí)符和命名規(guī)則詳解
這篇文章主要給大家介紹了關(guān)于java語言基礎(chǔ)之標(biāo)識(shí)符和命名規(guī)則的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03

