ThreadLocal
類在java中可以讓變量只能被相同的線程讀寫.那麼即便兩個線程同時訪問相同的代碼中的相同變量,也會產生兩個變量副本,變量副本分別僅對本線程可見. 在java中較爲典型的應用莫過於Servlet
的HttpServletRequest
了.html
done like this:java
private ThreadLocal myThreadLocal = new ThreadLocal();
複製代碼
以上代碼實例化了一個ThreadLocal
, ThreadLocal
在同一個線程中,僅須要被實例化一次便可.多個線程運行這段代碼時,每一個線程都會建立一個本身的ThreadLocal
副本,且僅對本線程可見.當兩個線程往ThreadLocal
設置不一樣值時,它們見不到對方設置的值.ide
ThreadLocal
建立完成後,能夠經過set()
來存儲值.post
done like this:this
myThreadLocal.set("test var")
複製代碼
能夠經過get()
來取得原先存儲的值.spa
done like this:線程
String myVar = (String)myThreadLocal.get();
複製代碼
調用get()
返回以前存儲的值,調用set()
方法,能夠傳遞一個Object
做爲存儲值.code
咱們能夠建立一個泛型化的ThreadLocal
,這樣在調用get()
就不用進行類型強轉了.htm
done like this:繼承
private ThreadLocal myThreadLocal = new ThreadLocal<String>();
複製代碼
這樣咱們能夠直接經過set()
來存儲目標類型值,經過get()
來取得目標類型值:
myThreadLocal.set("text var");
String myVar = myThreadLocal.get();
複製代碼
咱們知道經過調用set()
來存儲值僅會對當前線程可見,對其餘線程不可見.有時候咱們須要設置對全部線程可見的默認值.
這時咱們能夠繼承ThreadLocal
類並覆蓋initialValue()
.固然也能夠用使用匿名內部類的方式.
done like this:
private ThreadLocal myThreadLocal = new ThreadLocal<String>() {
@Override protected String initialValue() {
return "This is the initial value";
}
};
複製代碼
如今全部線程在沒有調用set()
的前提下,都能經過get()
來取得默認值.
public class ThreadLocalDemo {
private ThreadLocal<Integer> myThreadLocal = new ThreadLocal();
private AtomicInteger counter = new AtomicInteger();
private Runnable runnable = () -> {
Thread curThread = Thread.currentThread();
int count = counter.getAndIncrement();
System.out.println(curThread.getName() + ": set the val(" + count + ")");
myThreadLocal.set(count);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(curThread.getName() + ": get the val(" + myThreadLocal.get() + ")");
};
public static void main(String[] args) {
ThreadLocalDemo tld = new ThreadLocalDemo();
IntStream.range(1, 3)
.mapToObj(i -> new Thread(tld.runnable, "Thread-" + i))
.map(Thread::new)
.forEach(Thread::start);
}
}
複製代碼
咱們建立一個ThreadLocalDemo
用於示範ThreadLocal
的使用.首先咱們在內部實例化了ThreadLocal
用於存儲int
類型值,而後實例化AtomicInteger
用於產生不一樣的整數,再而後就是定義咱們的Runnable
.Runnable
中前後調用ThreadLocal
的set()
和get()
.set()
和get()
中間停頓了2s
鍾,用於預留時間讓線程對ThreadLocal
存儲值進行覆蓋,確保兩個線程都已經調用ThreadLocal
的set()
後再調用get()
.預期結果是每一個線程經過get()
取得都是以前經過set()
存儲的值.
執行結果:
Thread-0: set the val(0)
Thread-1: set the val(1)
Thread-0: get the val(0)
Thread-1: get the val(1)
由結果能夠看出ThreadLocal
存儲的值確實僅對本線程可見,若換成普通的變量結果應該是相似以下所示:
Thread-0: set the val(0)
Thread-1: set the val(1)
Thread-0: get the val(1)
Thread-1: get the val(1)
InheritableThreadLocal
是ThreadLocal
的子類.與ThreadLocal
不一樣的是InheritableThreadLocal
存儲值容許當前線程建立的全部子線程訪問.
該系列博文爲筆者複習基礎所著譯文或理解後的產物,複習原文來自Jakob Jenkov所著Java Concurrency and Multithreading Tutorial