ThreadLocal是一个关于创建线程局部变量的类。
一般情况我们创建的变量是可以被任何一个线程访问并修改的,而使用ThreadLocal创建的变量只能被当前线程访问,其他线程无法访问和修改。
ThreadLocal<T> 接口的方法也很简单,只有四个方法:
public class ThreadLocalDemo {
//通过匿名内部类创建一个ThreadLocal对象。
private static ThreadLocal<Integer> threadLocal=new ThreadLocal<Integer>(){
@Override
public Integer initialValue() {
return 0;
}
};
public static ThreadLocal<Integer> getThreadLocal() {
return threadLocal;
}
public int getNextNum(){
threadLocal.set(threadLocal.get()-1);
return threadLocal.get();
}
public static void main(String[] args){
ThreadLocalDemo threadLocalDemo=new ThreadLocalDemo();
new MyThread(threadLocalDemo).start();
new MyThread(threadLocalDemo).start();
new MyThread(threadLocalDemo).start();
}
private static class MyThread extends Thread{
private ThreadLocalDemo threadLocalDemo;
public MyThread(ThreadLocalDemo threadLocalDemo){
this.threadLocalDemo=threadLocalDemo;
}
@Override
public void run() {
super.run();
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName()+"................."+threadLocalDemo.getNextNum());
}
threadLocalDemo.getThreadLocal().remove();
}
};
}
由运行结果我们可以看出,虽然三个线程都是用了同一个ThreadLocalDemo 实例,但他们是互补影响的,都有自己独立的threadLocalDemo 数据,这就是为每个线程提供了一个单独的副本,不会影响其他线程对应的副本。
ThreadLocal的现象说完了,那么ThreadLocal是如何实现这种”每个线程都有自己的变量拷贝”的呢,下面看一下原理。
ThreadLocal实现原理
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
由set()方法可以看到,通过getMap(t)获取一个和当前线程相关的ThreadLocalMap ,然后将变量的值设置到这个ThreadLocalMap 对象中,如果获取到的是null,就creatMap(t,value)创建一个。
所以可以知道,线程隔离就在于ThreadLocalMap 中,ThreadLocalMap 是ThreadLocal类的一个静态内部类,它实现了键值对的设置和获取,每个线程都有一个独立的ThreadLocalMap 供这个线程读取和修改,从而实现了变量访问在不同线程中的隔离。
ThreadLocal在处理线程的局部变量时要比synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。