今天項目中遇到一個問題:利用SecurityContextHolder
獲取用戶登陸信息的時候一直報空指針異常。網上查詢原來這是一個線程級別的全局變量,只能在主線程上訪問。java
在Spring中,對例如如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等非線程安全狀態採用ThreadLocal進行處理,讓它們也成爲線程安全的狀態。安全
Threadlocal
是Thread的局部變量,它爲每一個使用該變量的線程提供獨立的變量副本。每個線程均可以獨立地改變本身的副本,而不會影響其它線程所對應的副本,最終目的是實現線程之間的數據隔離(有個關鍵字叫Synchronized
是實現線程之間的數據隔離)。ide
ThreadLocal
提供的四個方法做用以下:spa
- initialValue() //返回該線程局部變量的初始值 ,在get操做沒有對應的值時,調用此方法
- get() //返回當前線程所對應的線程變量副本
- set(Object value)//設置當前線程的線程變量副本
- remove() //將當前線程變量副本的值刪除
介紹原理以前須要瞭解另外兩個類:線程
- Thread //用於操做線程 ,內部有
ThreadLocal
和ThreadLocalMap
屬性- ThreadLocalMap //
ThreadLocal
內部類,用來存儲數據,存儲了以threadLocal爲key,須要隔離的數據爲value。
Thread內有個threadLocals,該屬性用來保存該線程本地變量。ThreadLocal進行set()和get()操做時都要首先獲取當前線程,而後獲取線程內的threadLocals,若是threadLocals存在,則以threadlocal爲key調取vlaue或set值。這樣每一個線程都有本身的數據,就作到了不一樣線程間數據的隔離,保證了數據安全。指針
public
class Thread implements Runnable {
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
複製代碼
public class ThreadLocalTest {
private static String s1;
private static ThreadLocal<String> s2 = new ThreadLocal<>();
public static void main(String[] args) {
s1 = "test1";
threadLabel.set("test1");
//開啓一個新線程,改變s1,s2的值
Thread thread = new Thread() {
@Override
public void run() {
s1= "test2";
s2.set("test2");
}
};
thread.start();
System.out.println("s1值爲" +s1 );//獲取到s1變化爲爲test2
System.out.println("s2值爲" +s2.get());//獲取到的s2仍然爲爲test1,在另外線程賦值對main線程無影響
}
}
複製代碼