当多线程访问共享可变数据时,涉及到线程间同步的问题,并不是所有时候,都要用到共享数据,所以就需要线程封闭出场了。
数据都被封闭在各自的线程之中,就不需要同步,这种通过将数据封闭在线程中而避免使用同步的技术称为线程封闭。
本文主要介绍线程封闭中的其中一种体现:ThreadLocal,将会介绍什么是 ThreadLocal;从 ThreadLocal 源码角度分析,最后介绍 ThreadLocal 的应用场景。
什么是 ThreadLocal?
ThreadLocal 是 Java 里一种特殊变量,它是一个线程级别变量,每个线程都有一个 ThreadLocal 就是每个线程都拥有了自己独立的一个变量,竞态条件被彻底消除了,在并发模式下是绝对安全的变量。
可以通过 ThreadLocal<T> value = new ThreadLocal<T>();
来使用。
会自动在每一个线程上创建一个 T 的副本,副本之间彼此独立,互不影响,可以用 ThreadLocal 存储一些参数,以便在线程中多个方法中使用,用以代替方法传参的做法。
下面通过例子来了解下 ThreadLocal:
public class ThreadLocalDemo {
/**
* ThreadLocal变量,每个线程都有一个副本,互不干扰
*/
public static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<>();
public static void main(String[] args) throws Exception {
new ThreadLocalDemo().threadLocalTest();
}
public void threadLocalTest() throws Exception {
// 主线程设置值
THREAD_LOCAL.set("wupx");
String v = THREAD_LOCAL.get();
System.out.println("Thread-0线程执行之前," + Thread.currentThread().getName() + "线程取到的值:" + v);
new Thread(new Runnable() {
@Override
public void run() {
String v = THREAD_LOCAL.get();
System.out.println(Thread.currentThread().getName() + "线程取到的值:" + v);
// 设置 threadLocal
THREAD_LOCAL.set("huxy");
v = THREAD_LOCAL.get();
System.out.println("重新设置之后," + Thread.currentThread().getName() + "线程取到的值为:" + v);
System.out.println(Thread.currentThread().getName() + "线程执行结束");
}
}).start();
// 等待所有线程执行结束
Thread.sleep(3000L);
v = THREAD_LOCAL.get();
System.out.println("Thread-0线程执行之后," + Thread.currentThread().getName() + "线程取到的值:" + v);
}
}
首先通过 static final
定义了一个 THREAD_LOCAL
变量,其中 static
是为了确保全局只有一个保存 String 对象的 ThreadLocal 实例;final
确保 ThreadLocal 的实例不可更改,防止被意外改变,导致放入的值和取出来的不一致,另外还能防止 ThreadLocal 的内存泄漏。上面的例子是演示在不同的线程中获取它会得到不同的结果,运行结果如下:
Thread-0线程执行之前,main线程取到的值:wupx
Thread-0线程取到的值:null
重新设置之后Thread-0线程取到的值为:huxy
Thread-0线程执行结束
Thread-0线程执行之后,main线程取到的值:wupx
首先在 Thread-0
线程执行之前,先给 THREAD_LOCAL
设置为 wupx
,然后可以取到这个值&#x