ThreadLocal,併發編程
ThreadLocal爲解決多線程程序的併發問題提供了一種新的思路。當使用ThreadLocal維護變量時,ThreadLocal爲每個使用該變量的線程提供獨立的變量副本,所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應的副本。
在ThreadLocal類中有一個Map,用於存儲每一個線程的變量副本,Map中元素的鍵爲線程對象,而值對應線程的變量副本。ThreadLocal中有四個方法:
1、get()方法是用來獲取ThreadLocal在當前線程中保存的變量副本
2、set()用來設置當前線程中變量的副本
3、remove()用來移除當前線程中變量的副本
4、initialValue()是一個protected方法,顯然是爲了讓子類覆蓋而設計的,返回此線程局部變量的當前線程的初始值
初始時,在Thread裏面,threadLocals爲空,當通過ThreadLocal變量調用get()方法或者set()方法,就會對Thread類中的threadLocals進行初始化。
在進行get之前,必須先set,否則會報空指針異常;
很多情況下,ThreadLocal比直接使用synchronized同步機制解決線程安全問題更簡單,更方便,且結果程序擁有更高的併發性。
ThreadLocal的使用方法和實現原理。
ThreadLocal,很多地方叫做線程本地變量,也有些地方叫做線程本地存儲
出於線程安全的考慮,必須將這段代碼的兩個方法進行同步處理,並且在調用connect的地方需要進行同步處理。
一個線程不需要關心其他線程是否對這個connect進行了修改的。
get()方法是用來獲取ThreadLocal在當前線程中保存的變量副本,set()用來設置當前線程中變量的副本,remove()用來移除當前線程中變量的副本,initialValue()是一個protected方法,一般是用來在使用時進行重寫的,它是一個延遲加載方法。
內部維護了一個ThreadLocalMap。
1)實際的通過ThreadLocal創建的副本是存儲在每個線程自己的threadLocals中的;
2)爲何threadLocals的類型ThreadLocalMap的鍵值爲ThreadLocal對象,因爲每個線程中可有多個threadLocal變量,就像上面代碼中的longLocal和stringLocal;
3)在進行get之前,必須先set,否則會報空指針異常;
ThreadLocal是什麼
早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal爲解決多線程程序的併發問題提供了一種新的思路。使用這個工具類可以很簡潔地編寫出優美的多線程程序。
當使用ThreadLocal維護變量時,ThreadLocal爲每個使用該變量的線程提供獨立的變量副本,所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應的副本。
從線程的角度看,目標變量就象是線程的本地變量,這也是類名中“Local”所要表達的意思。
/**
* Created on 2020/4/9 19:05
* author:crs
* Description: 測試ThreadLocal的使用
*/
public class TestThreadLocal {
ThreadLocal intThread= new ThreadLocal<Integer>();
ThreadLocal strThread= new ThreadLocal<String>();
public void init(){
//當前線程id和當前線程名稱
intThread.set(Thread.currentThread().getId());
strThread.set(Thread.currentThread().getName());
}
public Long getLong(){
return (Long) intThread.get();
}
public String getString(){
return (String) strThread.get();
}
public static void main(String[] args) throws InterruptedException {
TestThreadLocal testThreadLocal = new TestThreadLocal();
testThreadLocal.init();
System.out.println(testThreadLocal.getLong());
System.out.println(testThreadLocal.getString());
System.out.println("--->");
Thread thread = new Thread(){
@Override
public void run() {
//設置當前子線程的id和名稱
testThreadLocal.init();
System.out.println(testThreadLocal.getLong());
System.out.println(testThreadLocal.getString());
}
};
thread.start();
thread.join();
System.out.println("------>");
System.out.println(testThreadLocal.getLong());
System.out.println(testThreadLocal.getString());
}
}