原文链接:http://tutorials.jenkov.com/java-concurrency/threadlocal.html
摘要:这是翻译自一个大概30个小节的关于Java并发编程的入门级教程,原作者Jakob Jenkov,译者Zhenning Lang,转载请注明出处,thanks and have a good time here~~~(希望自己不要留坑)
Java 中的 ThreadLocal 类让你可以创建只能被相同的线程读写的变量。因此,即便是两个线程在执行同一段代码,同时这段代码拥有 ThreadLocal 变量的引用,此时,这两个线程的 ThreadLocal 变量对于对方都是不可见的。
1. 创建 ThreadLocal 变量
下面的例子展示了如何创建一个 ThreadLocal 变量:
private ThreadLocal myThreadLocal = new ThreadLocal();
上例创建并初始化了一个 ThreadLocal 对象。虽然多个线程都可以处理 ThreadLocal 变量(拥有 ThreadLocal 变量的引用),但每个线程只能获取其自己的 ThreadLocal 实例的值。
即便两个线程对同一个 ThreadLocal 对象设置了不同的值,这两个线程所设置的值对于对方也都是不可见的。
(通俗地讲,就是看起来好像每个线程都创建了该线程(Thread)的本地(Local)的变量一样,如果这个不大好理解,可以直接看第 5 部分的示例代码)
2. 读写 ThreadLocal 变量
一旦创建了 ThreadLocal 变量,你可以通过类似下面的代码来设置其取值:
myThreadLocal.set("A thread local value");
通过如下代码来读取 ThreadLocal 变量的值:
String threadLocalValue = (String) myThreadLocal.get();
ThreadLocal 变量的 get() 方法返回类型为 Object,而 set() 方法以 Object 对象作为输入函数。
3. ThreadLocal 范型
如果利用 ThreadLocal 范型则不必再对 get() 方法的返回值进行强制类型转换,例如:
private ThreadLocal<String> myThreadLocal = new ThreadLocal<String>();
此时,myThreadLocal 中只能存储 String 类型的变量。
myThreadLocal.set("Hello ThreadLocal");
String threadLocalValue = myThreadLocal.get();
4. 初始化 ThreadLocal 的值
由于 ThreadLocal 对象的值只对设置该值的对象是可见的,所以没有任何线程可以利用 set() 方法初始化一个对所有线程都可见的 ThreadLocal 的初始值。
取而代之的,可以通过继承 ThreadLocal 并覆盖 initialValue() 方法来指定其初始值,如下例所示:
private ThreadLocal myThreadLocal = new ThreadLocal<String>() {
@Override protected String initialValue() {
return "This is the initial value";
}
};
如此一来,所有使用 myThreadLocal 的线程在调用 set() 方法之前都可以通过 get() 方法获取这个初始值(”This is the initial value”)。
5. 完整的 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() 方法被声明为 synchronized 的(?),并且没有使用 ThreadLocal 对象,后被执行的线程将会覆盖先执行线程所写的值。
然而,由于使用了 ThreadLocal 类,则两个线程对于 ThreadLocal 对象所写的值将不会相互影响,即例子中会打印出不同的值。