ThreadLocal简介
ThreadLocal
线程封闭:每个Thread
线程内部都有一个map
,这个map
是以线程本地对象作为key
,以线程的变量副本作为Value
。同时这个map
是由TreadLoal
来维护的,由ThreadLocal
负责向map
里设置线程的变量值以及获取值。因此,即使两个线程正在执行相同的代码,并且代码具有对ThreadLocal变量的引用,那么两个线程也不能看到彼此的ThreadLocal变量,于是就形成了线程间副本的隔离,做到了多个线程互不干扰。
ThreadLocal使用
创建ThreadLocal
private ThreadLocal myThreadLocal = new ThreadLocal();
上面是一个简单的ThreadLocal
创建过程,通过实例化一个新的ThreadLocal
对象。每个线程只需要执行一次。即使不同的线程执行访问ThreadLocal
的相同代码,每个线程也只能看到自己的ThreadLocal
实例。即使两个不同的线程在同一个ThreadLocal
对象上设置了不同的值,它们也不能看到彼此的值。
访问ThreadLocal
给ThreadLocal
赋值:
myThreadLocal.set("A thread local value");
获取ThreadLocal
中的值
String threadLocalValue = (String) myThreadLocal.get();
当然我们也可以使用通用的方法
private ThreadLocal<String> myThreadLocal = new ThreadLocal<String>();
myThreadLocal.set("Hello ThreadLocal");
String threadLocalValue = myThreadLocal.get();
给ThreadLocal设置初始值
由于ThreadLocal
对象上设置的值只对设置值的线程可见,所以没有线程可以使用set()
在ThreadLocal
上设置初值,而set()
对所有线程可见。
不过这并不意味着我们不可以对ThreadLocal
设置初始值,实际上我们可以通过覆盖ThreadLocal
中的initialValue()
方法为其设置初始值。
private ThreadLocal myThreadLocal = new ThreadLocal<String>() {
@Override protected String initialValue() {
return "This is the initial value";
}
};
通过上述方法,在调用set()
之前调用get()
时,所有线程将看到相同的初始值。
ThreadLocal的完整使用用例
下面是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) {
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
}
}
这个例子创建了一个MyRunnable
实例,它被传递给两个不同的线程。两个线程都执行run()
方法,因此在ThreadLocal
实例上设置不同的值。如果对set()
调用的访问已经同步,并且它不是ThreadLocal
对象,那么第二个线程将覆盖第一个线程设置的值。
但是,由于它是ThreadLocal
对象,所以两个线程不能看到彼此的值。因此,它们设置并得到不同的值。