在項目中不少地方會用到ThreadLocal對象,用來實現線程之間資源隔離。現在通過圖的方式接解刨其原理。
public static void main(String[] arg) throws InterruptedException, IOException {
final ThreadLocal t = new ThreadLocal();
Thread thread_1 = new Thread(new Runnable(){
@Override
public void run() {
t.set("thread_1");
try {
Thread.sleep(50);
System.out.println("thread_1");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.get());
}
});
Thread thread_2 = new Thread(new Runnable(){
@Override
public void run() {
t.set("thread_2");
try {
Thread.sleep(50);
System.out.println("thread_2");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.get());
}
});
Thread thread_3 = new Thread(new Runnable(){
@Override
public void run() {
t.set("thread_3");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.get());
}
});
thread_1.start();
thread_2.start();
thread_3.start();
System.in.read();
Thread.currentThread().join();
整個過程的關鍵就是:
1、每個線程都有自己的ThreadLocalMap對象;(ThreadLocal 多線程下資源隔離的根本原因)
2、各個線程在調用同一個ThreadLocal對象的set(value)設置值的時候,是往各自的ThreadLocalMap對象數組中設置值
3、至於當前值放置在數組中的下標位置,則是通過ThreadLocal對象的threadLocalHashCode計算而來。即多線程環境下ThreadLocal對象的threadLocalHashCode是共享的。
4、而ThreadLocal對象的threadLocalHashCode是一個原子自增的變量,通過類方法初始化值。
也即,ThreadLocal a = new ThreadLocal();就會初始化threadLocalHashCode值,這個值不會再變。所以,同一個線程在同一個ThreadLocal對象中set()值,只能保存最後一次set的值。
5、爲什麼每個線程都有自己的ThreadLocalMap對象,且是一個數組呢?
答:根據以上的分析,多個線程操作一個ThreadLocal對象就能達到線程之間資源隔離。而採用數組是因爲可能一個線程需要通過多個ThreadLocal對象達到多個資源隔離。每個不同的ThreadLocal對象的threadLocalHashCode都不一樣,也就映射到ThreadLocalMap對象數組下的不同下標。
6、每個線程的ThreadLocalMap對象是通過偏移位置的方式解決hash碰撞
7、每個線程都有自己的ThreadLocalMap對象也有擴容機制,且是天然線程安全的