今天项目中遇到一个问题:利用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线程无影响
}
}
复制代码