Java并發(fā)編程之threadLocal
1、ThreadLocal介紹
多個線程訪問同一個共享變量時特別容易出現(xiàn)并發(fā)問題,特別是多線程需要對共享變量進行寫入時。為了保證線程安全,一般使用者在訪問共享變量的時候需要進行適當?shù)耐?,如圖
同步的一般措施是加鎖,這就需要使用者對鎖有一定的了解,這顯然加重了使用者的負擔,那么有沒有一種方法可以做到,當創(chuàng)建一個變量后,每個線程對其進行訪問的時候訪問的是自己線程的變量呢?其實ThreadLocal
就可以做到。
ThreadLocal
是JDK
包提供的,它提供了線程本地變量,也就是說如果創(chuàng)建了一個ThreadLocal
變量,那么訪問這個變量的每一個線程都會有這個變量的一個本地副本。當多線程操作這個變量的時候,實際操作的就是自己本地內(nèi)存的里面的里面的變量,從而避免了線程安全問題。創(chuàng)建一個ThreadLocal
變量后,每一個線程都會復制一個變量到自己的本地內(nèi)存。
2、ThreadLocal使用實例
package com.heiye.learn1; public class ThreadLocalTest { //print方法 static void print(String threadName) { //打印當前線程本地內(nèi)存中LocalVariable變量的值 System.out.println(threadName + ":" + localVariable.get()); //清除當前線程本地內(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è)置了一個值,這其實設(shè)置的就是線程one本地內(nèi)存中對于threadLocal變量的一個副本。這個副本是線程two訪問不了的。
如果清除當前線程本地內(nèi)存中的localVariable
變量值,也就是執(zhí)行localVariable.remove()
;則:
3、ThreadLocal實現(xiàn)原理
首先查看一下ThreadLocal
類圖結(jié)構(gòu)
由該圖可知,Thread
類有一個ThreadLocals
和inheritableThreadLocals
,它們都是ThreadLocalMap
類型的變量,而ThreadLocalMap
是一個定制化的HashMap
。在默認的情況下,每個線程中的兩個變量都為null,只有當?shù)谝粋€線程調(diào)用ThreadLocal
的set或者get方法時才會創(chuàng)建它們,其實每個線程得到本地變量不是存放在ThreadLocal
實例里面,而是存放在具體的線程內(nèi)存空間里。ThreadLocal
就是一個工具殼,它通過set方法把value值存放在調(diào)用線程的threadlocals
里面并存放起來,當調(diào)用線程調(diào)用它的get()方法的時候,再從當前線程的threadLocals
變量里面將其拿出來使用。
分析set
,get
,remove
邏輯
//set public void set(T value) { //獲取當前線程 Thread t = Thread.currentThread(); //將當前線程作為key,到ThreadLocalMap取查找對應(yīng)的線程變量 ThreadLocalMap map = getMap(t); //如果找到,則設(shè)置 if (map != null) map.set(this, value); else //第一次調(diào)用就創(chuà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); }
在每一個線程內(nèi)都有一個名為threadLocals
的成員變量,該變量的類型為HashMap
,其中的key為我們定義的threadLocal
變量的this引用,value
為我們使用set方法設(shè)置的值。每個線程的本地變量存放在自己的內(nèi)存變量ThreadLocals
中,如果當前線程一直不消亡,那么這些本地變量會一直存在,所有可能造成內(nèi)存溢出。
到此這篇關(guān)于Java并發(fā)編程 threadLocal 的文章就介紹到這了,更多相關(guān)threadLocal 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring rest接口中的LocalDateTime日期類型轉(zhuǎn)時間戳
這篇文章主要介紹了Spring rest接口中的LocalDateTime日期類型轉(zhuǎn)時間戳的方法,Java程序中一般將日期類型定義為LocalDateTime,數(shù)據(jù)庫中保存的時間是0時區(qū)的時間2023-03-03springboot結(jié)合mysql主從來實現(xiàn)讀寫分離的方法示例
這篇文章主要介紹了springboot結(jié)合mysql主從來實現(xiàn)讀寫分離的方法示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-04-04springboot后端如何實現(xiàn)攜帶token登陸
這篇文章主要介紹了springboot后端如何實現(xiàn)攜帶token登陸,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-11-11Spring Boot2.0中SpringWebContext找不到無法使用的解決方法
這篇文章主要給大家介紹了關(guān)于Spring Boot2.0中SpringWebContext找不到無法使用的解決方法,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起學習學習吧2018-12-12Java使用黑盒方式模擬實現(xiàn)內(nèi)網(wǎng)穿透
這篇文章主要介紹了Java使用黑盒方式模擬實現(xiàn)內(nèi)網(wǎng)穿透,內(nèi)網(wǎng)穿透,也即 NAT 穿透,進行 NAT 穿透是為了使具有某一個特定源 IP 地址和源端口號的數(shù)據(jù)包不被 NAT 設(shè)備屏蔽而正確路由到內(nèi)網(wǎng)主機,需要的朋友可以參考下2023-05-05SpringCloud maven-assembly-plugin 多級目錄打包的實現(xiàn)
本文主要介紹了SpringCloud maven-assembly-plugin 多級目錄打包的實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-10-10