ThreadLocal
先看不使用ThreadLocal的例子:
package ch1.base.threadlocal;
public class NoThreadLocal {
static Integer count = new Integer(1);
public static class TestTask implements Runnable{
int id;
public TestTask(int id){
this.id =id;
}
public void run(){
System.out.println(Thread.currentThread().getName()+":start");
count = count+1;
System.out.println(Thread.currentThread().getName()+":"+count);
}
}
//運(yùn)行三個(gè)線程
public void StartThreadArray(){
Thread[] runs = new Thread[3];
for(int i=0;i<runs.length;i++){
runs[i] = new Thread(new TestTask(i));
}
for(int i=0;i<runs.length;i++){
runs[i].start();
}
}
public static void main(String[] args) {
NoThreadLocal noThreadLocal = new NoThreadLocal();
noThreadLocal.StartThreadArray();
}
}
/*
輸出:
Thread-1:start
Thread-0:start
Thread-0:3
Thread-2:start
Thread-1:2
Thread-2:4
Process finished with exit code 0
*/
再來(lái)看使用ThreadLocal的例子
package ch1.base.threadlocal;
//演示ThreadLocal的使用
public class UseThreadLocal {
private static ThreadLocal<Integer> intLocal = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
return 1;
}
};
private static ThreadLocal<String> stringThreadLocal;
//測(cè)試線程峰搪,線程的工作是將ThreadLocal變量的值變化量愧,并寫回狡刘,看看線程之間是否會(huì)互相影響
public static class TestThread implements Runnable{
int id;
public TestThread(int id){
this.id = id;
}
public void run(){
System.out.println(Thread.currentThread().getName()+": start");
Integer s = intLocal.get();
s=s+id;
intLocal.set(s);
System.out.println(Thread.currentThread().getName()+":"+intLocal.get());
// intLocal.remove();
}
}
//運(yùn)行三個(gè)線程
public void runThreadThree(){
Thread[] runs = new Thread[3];
for(int i=0;i<runs.length;i++){
runs[i] = new Thread(new TestThread(i));
}
for(int i=0;i<runs.length;i++){
runs[i].start();
}
}
public static void main(String[] args) {
UseThreadLocal test = new UseThreadLocal();
test.runThreadThree();
}
}
/*
Thread-0: start
Thread-1: start
Thread-2: start
Thread-0:1
Thread-1:2
Thread-2:3
Process finished with exit code 0
*/
基礎(chǔ)
ThreadLocal是一個(gè)關(guān)于創(chuàng)建線程局部變量的類。
通常情況下禁偎,我們創(chuàng)建的變量是可以被任何一個(gè)線程訪問(wèn)并修改的。而使用ThreadLocal創(chuàng)建的變量只能被當(dāng)前線程訪問(wèn),其他線程則無(wú)法訪問(wèn)和修改身诺。
有一個(gè)誤區(qū)是ThreadLocal的目的是為了解決多線程訪問(wèn)資源時(shí)的共享問(wèn)題 但ThreadLocal 并不解決多線程 共享 變量的問(wèn)題。既然變量不共享抄囚,那就更談不上同步的問(wèn)題霉赡。
理解
ThreadLoal 變量,它的基本原理是幔托,同一個(gè) ThreadLocal 所包含的對(duì)象(對(duì)ThreadLocal< String >而言即為 String 類型變量)穴亏,在不同的 Thread 中有不同的副本(實(shí)際是不同的實(shí)例)。這里有幾點(diǎn)需要注意
因?yàn)槊總€(gè) Thread 內(nèi)有自己的實(shí)例副本重挑,且該副本只能由當(dāng)前 Thread 使用嗓化。這是也是 ThreadLocal 命名的由來(lái)
既然每個(gè) Thread 有自己的實(shí)例副本,且其它 Thread 不可訪問(wèn)谬哀,那就不存在多線程間共享的問(wèn)題
既無(wú)共享刺覆,何來(lái)同步問(wèn)題,又何來(lái)解決同步問(wèn)題一說(shuō)史煎?
那 ThreadLocal 到底解決了什么問(wèn)題谦屑,又適用于什么樣的場(chǎng)景驳糯?
This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its get or set method) has its own, independently initialized copy of the variable. ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).
Each thread holds an implicit reference to its copy of a thread-local variable as long as the thread is alive and the ThreadLocal instance is accessible; after a thread goes away, all of its copies of thread-local instances are subject to garbage collection (unless other references to these copies exist).
核心意思是
ThreadLocal 提供了線程本地的實(shí)例。它與普通變量的區(qū)別在于氢橙,每個(gè)使用該變量的線程都會(huì)初始化一個(gè)完全獨(dú)立的實(shí)例副本酝枢。ThreadLocal 變量通常被private static修飾。當(dāng)一個(gè)線程結(jié)束時(shí)悍手,它所使用的所有 ThreadLocal 相對(duì)的實(shí)例副本都可被回收帘睦。
總的來(lái)說(shuō),ThreadLocal 適用于每個(gè)線程需要自己獨(dú)立的實(shí)例且該實(shí)例需要在多個(gè)方法中被使用坦康,也即變量在線程間隔離而在方法或類間共享的場(chǎng)景竣付。這讓我想到了Js中的一個(gè)特性:閉包.閉包下的所有變量都是只屬于自己的,而ThreadLocal就是只屬于線程自己的對(duì)象. 另外,該場(chǎng)景下滞欠,并非必須使用 ThreadLocal 卑笨,其它方式完全可以實(shí)現(xiàn)同樣的效果,只是 ThreadLocal 使得實(shí)現(xiàn)更簡(jiǎn)潔仑撞。
參考:https://blog.csdn.net/qq_30054997/article/details/81515668