ThreadLocal
創(chuàng)新互聯(lián)長期為超過千家客戶提供的網(wǎng)站建設服務,團隊從業(yè)經(jīng)驗10年,關注不同地域、不同群體,并針對不同對象提供差異化的產品和服務;打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為興山企業(yè)提供專業(yè)的成都網(wǎng)站建設、網(wǎng)站制作,興山網(wǎng)站改版等技術服務。擁有10多年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。
概述
一、對ThreadLocal的理解
1.1 ThreadLocal在JDK中的定義
1.2 應用場景
二、深入分析ThreaLocal類
2.1 get()
2.2 setIntialValue()
2.3 ThreadLocal類是如何為每個線程創(chuàng)建變量副本
三、ThreadLocal的應用場景
3.1 數(shù)據(jù)庫連接問題
3.2 Session管理
3.3 Thread-per-Request(一個請求對應一個服務器線程)
四、ThreadLocal的一般使用步驟
概述
本文借鑒了Java 并發(fā)編程這篇博主專欄的文章,他的專欄寫的很好,推薦!
ThreadLocal 又名 線程局部變量 ,是 Java 中一種較為特殊的線程綁定機制,可以為每一個使用該變量的線程都提供一個變量值的副本,并且每一個線程都可以獨立地改變自己的副本,而不會與其它線程的副本發(fā)生沖突。
一般而言,通過 ThreadLocal 存取的數(shù)據(jù)總是與當前線程相關,也就是說,JVM 為每個運行的線程綁定了私有的本地實例存取空間,從而為多線程環(huán)境常出現(xiàn)的并發(fā)訪問問題提供了一種 隔離機制 。
如果某個變量要被某個線程獨享,那么我們就可以通過ThreadLocal來實現(xiàn)本地存儲功能;
一、對ThreadLocal的理解
1.1 ThreadLocal在JDK中的定義
每個線程都有關于該 ThreadLocal變量 的私有值 ,并且對其他線程是不可見的;
ThreadLocal 可以給定一個獨立于變量的初始值,這樣每個線程就會獲得這個初始化值的一個拷貝,并且每個線程對這個值的修改對其他線程是不可見的;
ThreadLocal的一個重要作用是就是將類的狀態(tài)與線程關聯(lián)起來,解決方案就是在這個類中定義一個 private static ThreadLocal 實例;
1.2 應用場景
類 ThreadLocal 主要解決的就是為每個線程綁定自己的值,以方便其處理自己的狀態(tài);
形象地講,可以將 ThreadLocal變量 比喻成全局存放數(shù)據(jù)的盒子,盒子中可以存儲每個線程的私有數(shù)據(jù)。例如,以下類用于生成對每個線程唯一的局部標識符。線程 ID 是在第一次調用 uniqueNum.get() 時分配的,在后續(xù)調用中不會更改;
二、深入分析ThreaLocal類
ThreadLocal中,一共提供了四個方法:
public T get() { }
public void set(T value){ }
public void remove(){ }
protected T initialValue{ }
1
2
3
4
get() 獲取ThreadLocal變量在當前線程中保存的值;
set() 設置ThreadLocal在當前線程的值;
remove() 用來移除當前線程中相關ThreadLocal變量;
initialValue() 是一個protected方法,一般需要重寫;
2.1 get()
源碼如下:
public T get(){
Thread t = Thread.currentThread();//獲取當前線程對象
ThreadLocalMap map = getMap(t);
if(map!=null){
//從當前線程的ThreadLocalMap獲取該thread-local variable對應的entry
ThreadLocalMap.Entry e = map.getEntry(this);
if(e!=null)
return (T)e.value;//取得目標值
}
return setInitialValue();
}
1
2
3
4
5
6
7
8
9
10
11
2.2 setIntialValue()
private T setIntialValue(){
T value = initialValue(); //默認實現(xiàn)返回null
Thread t = Thread.currentThread();//獲得當前線程;
ThreadLocalMap map = getMap(t);//得到當前線程ThreadLocalMap類型域threadLocals
if(map!=null)
map.set(this,value);//該 map 的鍵是當前 ThreadLocal 對象
else?
createMap(t,value);
return value;
}
1
2
3
4
5
6
7
8
9
10
initialValue()
? ? protected T initialValue() {
? ? ? ? return null;? ? ? ? ? ? // 默認實現(xiàn)返回 null
? ? }
1
2
3
createMap()
? ? void createMap(Thread t, T firstValue) {
? ? ? ? t.threadLocals = new ThreadLocalMap(this, firstValue); // this 指代當前 ThreadLocal 變量,為 map 的鍵??
? ? }
1
2
3
2.3 ThreadLocal類是如何為每個線程創(chuàng)建變量副本
每個線程內部有一個 ThreadLocal.ThreadLocalMap 類型的成員變量 threadLocals,這個 threadLocals 存儲了與該線程相關的所有 ThreadLocal 變量及其對應的值(”ThreadLocal 變量及其對應的值” 就是該Map中的一個 Entry)。 Key 是 ThreadLocal 變量, Value 是該 ThreadLocal 變量對應的值;
初始時,Thread里面的threadlocals為空,當ThreadLocal變量調用**get()方法或者set()**就會對Thread類中的threadlocals進行初始化,并且以當前ThreadLocal變量為鍵值,以ThreadLocal要保存的值為value,存到 threadLocals;
然后在當前線程里面,如果要使用ThreadLocal對象,就可以通過get方法獲得該線程的threadLocals,然后以該ThreadLocal對象為鍵取得其對應的 Value,也就是ThreadLocal對象中所存儲的值;
三、ThreadLocal的應用場景
Java 中,類 ThreadLocal 解決的是變量在不同線程間的隔離性。最常見的 ThreadLocal 使用場景有 數(shù)據(jù)庫連接問題、Session管理等。
3.1 數(shù)據(jù)庫連接問題
private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() {
? ? public Connection initialValue() {
? ? ? ? return DriverManager.getConnection(DB_URL);
? ? }
};
public static Connection getConnection() {
? ? return connectionHolder.get();
}
1
2
3
4
5
6
7
8
9
3.2 Session管理
private static final ThreadLocal threadSession = new ThreadLocal();
public static Session getSession() throws InfrastructureException {
? ? Session s = (Session) threadSession.get();
? ? try {
? ? ? ? if (s == null) {
? ? ? ? ? ? s = getSessionFactory().openSession();
? ? ? ? ? ? threadSession.set(s);
? ? ? ? }
? ? } catch (HibernateException ex) {
? ? ? ? throw new InfrastructureException(ex);
? ? }
? ? return s;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
3.3 Thread-per-Request(一個請求對應一個服務器線程)
在經(jīng)典Web交互模型中,請求的處理基本上采用的都是“一個請求對應一個服務器線程”的處理方式,因此就可以將請求設置成類似ThreadLocal的形式,這樣,當某個服務器線程來處理請求時,就可以獨享該請求的處理;
四、ThreadLocal的一般使用步驟
ThreadLocal使用步驟一般分為三步:
創(chuàng)建一個ThreadLocal對象threadXxx,用來保存線程間需要隔離處理的對象xxx;
提供一個獲取要隔離訪問的數(shù)據(jù)的方法 getXxx(),在方法中判斷,若 ThreadLocal對象為null時候,應該 new() 一個隔離訪問類型的對象;
在線程類的run()方法中,通過getXxx()方法獲取要操作的數(shù)據(jù),這樣可以保證每個線程對應一個數(shù)據(jù)對象,在任何時刻都操作的是這個對象,不會交叉。
————————————————
本文題目:Java并發(fā)編程——ThreadLocal
轉載源于:http://jinyejixie.com/article32/pggopc.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供標簽優(yōu)化、搜索引擎優(yōu)化、面包屑導航、虛擬主機、網(wǎng)站設計公司、Google
聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)