要想在多个类中访问同一个值,通常会用到静态成员。但是在多线程环境下,对静态成员就会出现你存我取的现象。如何保证静态成员不会被其他的线程访问呢?这就要用到 ThreadLocal。下面是两个例子:
/**
* 演示 ThreadLocal 的使用
*/
public class ThreadLocalTest {
// ThreadLocal 是一个泛型容器
private static ThreadLocal<String> threadName = new ThreadLocal<String>();
// 将对象放入 ThreadLocal
public static void setThreadName(String name) {
threadName.set(name);
}
// 从 ThreadLocal 中读取内容
public static String getThreadName() {
return threadName.get();
}
// 程序入口
public static void main(String[] args) throws Exception {
// 启动 5 个线程。它们隔一段时间输出一行文字。
// 文字的内容是从同一个静态方法中取出来的,但
// 这 5 个线程输出的内容各不相同。这是因为使用
// 了 ThreadLocal。
for (int i = 0; i < 5; i++) {
new TestThread(i).start();
Thread.sleep(500);
}
}
// 测试线程
private static class TestThread extends Thread {
private int index;
// 注意这个方法的执行仍然是在主线程中
public TestThread(int index) {
this.index = index;
}
// 这里才是在新的线程中执行
@Override
public void run() {
ThreadLocalTest.setThreadName("Thread " + index);
while (true) {
System.out.println(ThreadLocalTest.getThreadName() + " ticks.");
try {
sleep(3000);
} catch (InterruptedException e) {
// nothing to do
}
}
}
}
}
/**
* 演示 ThreadLocal 的使用
*/
public class ThreadLocalTest2 {
private String threadName;
private ThreadLocal<String> threadNameLocal = new ThreadLocal<String>();
public String getThreadName() {
return threadName;
}
public void setThreadName(String threadName) {
this.threadName = threadName;
}
public String getThreadNameLocal() {
return threadNameLocal.get();
}
public void setThreadNameLocal(String nameLocal) {
threadNameLocal.set(nameLocal);
}
// 程序入口
public static void main(String[] args) throws Exception {
final ThreadLocalTest2 testObject = new ThreadLocalTest2();
// 启用三个线程同时操作 testObject
for (int i = 0; i < 3; i++) {
final int n = i;
new Thread() {
private int id = n;
@Override
public void run() {
try {
// 可以在输出中看到,每个线程在设置了 theadName 之后,再取出来时已经是一个不同的值;
// 而每个线程在设置了 theadNameLocal,再取出来还是原来的值。
testObject.setThreadName(String.valueOf(this.hashCode()));
System.out.println("线程 " + id + " 设置 theadName 为 " + this.hashCode());
testObject.setThreadNameLocal(String.valueOf(this.hashCode()));
System.out.println("线程 " + id + " 设置 theadNameLocal 为 " + this.hashCode());
Thread.sleep(200);
System.out.println("线程 " + id + " 获取 theadName 为 " + testObject.getThreadName());
System.out.println("线程 " + id + " 获取 theadNameLocal 为 " + testObject.getThreadNameLocal());
} catch (InterruptedException e) {
// nothing to do
}
}
}.start();
Thread.sleep(100);
}
}
}