ThreadLocal(一)
- 概述
官方说明:
This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its {@code get} or {@code set} method) has its own, independently initialized copy of the variable. {@code ThreadLocal} instances are typically private static fields in classes that wish to associate state with a thread (e.g.,a user ID or Transaction ID).
翻译过来的大概意思是:ThreadLocal类用来提供线程内部的局部变量。这些变量和线程内其他的变量不同。ThreadLocal类型的变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程里的变量独立于其他线程内的变量。ThreadLocal实例通常都是private static类型。
很多文章将ThreadLocal与线程同步机制混为一谈,特别注意的是ThreadLocal与线程同步无关,并不是为了解决多线程共享变量问题!
- 使用示例
/**
* 序列号生成器.内部使用ThreadLocal<Integer>存储序列号
*/
public class SequenceNumber {
/**
* ①通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值
*/
private ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {
@Override
public Integer initialValue() {
return 0;
}
};
/**
* ②获取下一个序列值
* @return
*/
public int getNextNum() {
seqNum.set(seqNum.get() + 1);
return seqNum.get();
}
public void remove() {
seqNum.remove();
}
}
public class TestClient implements Runnable {
private SequenceNumber sn;
public TestClient(SequenceNumber sn) {
super();
this.sn = sn;
}
@Override
public void run() {
for (int i = 0; i < 3; i++) {
// ④每个线程打出3个序列值
System.out.println("thread[" + Thread.currentThread().getName()
+ "] sn[" + sn.getNextNum() + "]");
}
}
public static void main(String[] args) {
SequenceNumber sn = new SequenceNumber();
// ③ 3个线程共享sn,各自产生序列号
TestClient t1 = new TestClient(sn);
TestClient t2 = new TestClient(sn);
TestClient t3 = new TestClient(sn);
new Thread(t1).start();
new Thread(t2).start();
new Thread(t3).start();
}
上面的代码TestClient的测试函数main,生成了三个线程,三个线程共享一个序列号生成对象。从多线程的角度考虑,三个线程运行产生的序列号应该各不相同。下面看运行结果:
thread[Thread-0] sn[1]
thread[Thread-0] sn[2]
thread[Thread-0] sn[3]
thread[Thread-1] sn[1]
thread[Thread-1] sn[2]
thread[Thread-1] sn[3]
thread[Thread-2] sn[1]
thread[Thread-2] sn[2]
thread[Thread-2] sn[3]
三个线程生成的序列号是相同的1到3。
这说明虽然在构造TestClient对象时用的同一个SequenceNumber对象。但是在使用SequenceNumber对象时,SequenceNumber对象里面的ThreadLocal<Integer> seqNum不是一个。