ThreadLocal
类可以让你创建只被同一个线程读取和写入的变量,其他线程都不能做到,即使是在多个线程执行的是同一段代码的情况下,这些线程都不能看到彼此的 ThreadLocal 变量域。
创建 ThreadLocal
private ThreadLocal myThreadLocal = new ThreadLocal();
每个线程实例化一次 ThreadLocal
对象。这样即使是多个线程执行同一段代码访问同一个 ThreadLocal 变量,但是每个线程只能看到私有的 ThreadLocal
实例。这样,即使不同的线程给同一个 ThreadLocal 对象设置不同的值,都对彼此不可见。
访问 ThreadLocal
设置值
myThreadLocal.set("A thread local value");
读取值
String threadLocalValue = (String) myThreadLocal.get();
ThreadLocal 泛型
你可以创建一个泛型化的 ThreadLocal
,这样使用 get()
方法的时候,就不需要类型转换了。
private ThreadLocal<String> myThreadLocal = new ThreadLocal<String>();
这样,你就只能存储字符串类型的值了
myThreadLocal.set("Hello ThreadLocal");
String threadLocalValue = myThreadLocal.get();
ThreadLocal 初始值
因为 ThreadLocal 中的值只对当前线程可见,无法做到为 ThreadLocal 设置对所有线程可见的初始值。如果想为 ThreadLocal 设置一个对所有线程可见的初始值,可以创建一个 ThreadLocal
的子类,并重写 initialValue()
方法
private ThreadLocal myThreadLocal = new ThreadLocal<String>() {
@Override
protected String initialValue() {
return "This is the initial value";
}
};
现在,所有线程都可以在调用 myThreadLocal.set()
方法之前去调用 myThreadLocal.get()
获取到同样的初始值了。
完整的 ThreadLocal 例子
public class ThreadLocalExample {
public static class MyRunnable implements Runnable {
private ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
@Override
public void run() {
threadLocal.set((int) (Math.random() * 100D));
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
System.out.println(threadLocal.get());
}
}
public static void main(String[] args) throws InterruptedException {
MyRunnable sharedRunnableInstance = new MyRunnable();
Thread thread1 = new Thread(sharedRunnableInstance);
Thread thread2 = new Thread(sharedRunnableInstance);
thread1.start();
thread2.start();
thread1.join(); // wait for thread 1 to terminate
thread2.join(); // wait for thread 2 to terminate
}
}
这两个线程都不能看到对方的值,所以它们 set/get 了不同的值。
InheritableThreadLocal
InheritableThreadLocal
是 ThreadLocal
的子类。与每个线程持有自己的 ThreadLocal
中的值不同,InheritableThreadLocal
允许一个线程创建的所有子线程访问父线程的值。