线程知识-ThreadLocal使用详解
生活随笔
收集整理的這篇文章主要介紹了
线程知识-ThreadLocal使用详解
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
最近在看Spring的時候回顧了一下ThreadLocal,下面是ThreadLocal的使用說明。
概述
首先,談到ThreadLocal的使用,我們先來了解一下ThreadLocal是什么?ThreadLocal是在JDK1,2的版本中開始提供的,他不是一個線程,而是一個線程的本地化對象。當某個變量在使用ThreadLocal進行維護時,ThreadLocal為使用該變量的每個線程分配了一個獨立的變量副本,每個線程可以自行操作自己對應的變量副本,而不會影響其他線程的變量副本。從線程的角度看,每個線程都保持一個對其線程局部變量副本的隱式引用,只要線程是活動的并且 ThreadLocal 實例是可訪問的;在線程消失之后,其線程局部實例的所有副本都會被垃圾回收(除非存在對這些副本的其他引用)。
?
通過ThreadLocal存取的數據,總是與當前線程相關,也就是說,JVM 為每個運行的線程,綁定了私有的本地實例存取空間,從而為多線程環境常出現的并發訪問問題提供了一種隔離機制。
?
ThreadLocal是如何做到為每一個線程維護變量的副本的呢?其實實現的思路很簡單,在ThreadLocal類中有一個Map,用于存儲每一個線程的變量的副本。
ThreadLocal的API
ThreadLocal的API提供了如下的4個方法,分別是:
T get()
? ? ? ? ? 返回此線程局部變量的當前線程副本中的值,如果這是線程第一次調用該方法,則創建并初始化此副本。
?
protected ?T initialValue()
? ? ? ? ? 返回此線程局部變量的當前線程的初始值。最多在每次訪問線程來獲得每個線程局部變量時調用此方法一次,即線程第一次使用 get() 方法訪問變量的時候。如果線程先于 get 方法調用 set(T) 方法,則不會在線程中再調用 initialValue 方法。 若該實現只返回 null;如果程序員希望將線程局部變量初始化為 null 以外的某個值,則必須為 ThreadLocal 創建子類,并重寫此方法。通常,將使用匿名內部類。initialValue 的典型實現將調用一個適當的構造方法,并返回新構造的對象。
void remove()
? ? ? ? ? 移除此線程局部變量的值。這可能有助于減少線程局部變量的存儲需求。如果再次訪問此線程局部變量,那么在默認情況下它將擁有其 initialValue。
?
void set(T value)
? ? ? ? ? 將此線程局部變量的當前線程副本中的值設置為指定值。許多應用程序不需要這項功能,它們只依賴于 initialValue() 方法來設置線程局部變量的值。
?
在程序中一般都重寫initialValue方法,以給定一個特定的初始值。
在上面的概述中也說到,其實ThreadLocal就是Map的一個應用,下面來看一個ThreadLocal實現的簡單模擬版本。
ThreadLocal簡單模擬實現
package org.lmu.threadlocal;import java.util.Collections; import java.util.HashMap; import java.util.Map;public class ThreadLocal<T> {private Map<Thread,T> map = Collections.synchronizedMap(new HashMap<Thread, T>());/*** 取得線程局部變量的值* @return 線程局部變量的值*/public T get(){Thread currenThread = Thread.currentThread();T temp = map.get(currenThread);//取得線程局部變量的值if(temp==null&&map.containsKey(currenThread)){temp = initialValue();map.put(currenThread, temp);} return temp;}/*** 設置當前線程局部變量的值* @param value 局部變量需設的值*/public void set(T value){ map.put(Thread.currentThread(), value);}/*** 將線程局部變量的值刪除*/public void remove(){map.remove(Thread.currentThread());}/*** 線程局部變量初始值* @return 初始值為null*/public T initialValue(){return null;} }
ThreadLocal實例
package org.lmu.threadlocal;public class ThreadLocalTest {//通過覆寫ThreadLocal中的initialValue方法為線程局部變量初始化之為0ThreadLocal<Integer> tlNum = new ThreadLocal<Integer>(){protected Integer initialValue() { return 0;}};/*** * @return 下一個值*/public int getNextNum(){Integer num = tlNum.get();//取得下一個值tlNum.set(num+1);//設置下一個值return num;//返回取得的值}private static class TestThread implements Runnable{private ThreadLocalTest tlt;public TestThread(ThreadLocalTest tlt) {this.tlt = tlt;}public void run() {int n = 3;for (int i = 0; i < n; i++) {System.out.println("線程【"+Thread.currentThread().getName()+"】-線程變量值【"+tlt.getNextNum()+"】");}}} public static void main(String[] args) {TestThread tt1 = new TestThread(new ThreadLocalTest());TestThread tt2 = new TestThread(new ThreadLocalTest());TestThread tt3 = new TestThread(new ThreadLocalTest());Thread t1 = new Thread(tt1);Thread t2 = new Thread(tt2);Thread t3 = new Thread(tt3);t1.start();t2.start();t3.start();} } 上面的例子中使用ThreadLocal來維護數值變量,初始值設置為0,,并在線程實現中打印3個序列值,這里提供3個線程進行測試,下面是測試的結果。線程【Thread-2】-線程變量值【0】
線程【Thread-1】-線程變量值【0】
線程【Thread-0】-線程變量值【0】
線程【Thread-1】-線程變量值【1】
線程【Thread-2】-線程變量值【1】
線程【Thread-1】-線程變量值【2】
線程【Thread-0】-線程變量值【1】
線程【Thread-0】-線程變量值【2】
線程【Thread-2】-線程變量值【2】
從結果中可以看到,每個線程都可以獨立的操作對應的副本,不會出現相互干擾的情況。
ThreadLocal與Thread同步機制的比較
在同步機制中,通過對象所機制保證同一個時間只能有一個線程訪問變量。而ThreadLocal則從列一個角度來解決多線程的并發訪問。概括起來說,對于多線程資源共享的問題,同步機制采用了“以時間換空間”的方式,而ThreadLocal采用了“以空間換時間”的方式。前者僅提供一份變量,讓不同的線程排隊訪問,而后者為每一個線程都提供了一份變量,因此可以同時訪問而互不影響。
?
轉載于:https://www.cnblogs.com/dyllove98/p/3144867.html
總結
以上是生活随笔為你收集整理的线程知识-ThreadLocal使用详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .configure
- 下一篇: 窗体显示