package threadLocalTest;
import threadLocalTest.TestNum.TestClient;
class TestNum {
// 通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值
// multiple thread can share with this value, but each thread has its dedicated value
private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {
public Integer initialValue() {
return 0;
}
}; // 获取下一个序列值
public int getNextNum() {
seqNum.set(seqNum.get() + 1);
return seqNum.get();
}
static class TestClient extends Thread {
private TestNum sn;
public TestClient(TestNum sn) {
this.sn = sn;
}
public void run() {
for (int i = 0; i < 3; i++) {
// 每个线程打出3个序列值
System.out.println("thread[" + Thread.currentThread().getName()
+ "] --> sn[" + sn.getNextNum() + "]");
}
}
}
}
public class LocalTest{
public static void main(String[] args) {
TestNum sn = new TestNum(); // 3个线程共享sn,各自产生序列号
TestClient t1 = new TestClient(sn);
TestClient t2 = new TestClient(sn);
TestClient t3 = new TestClient(sn);
t1.start();
t2.start();
t3.start();
}
}
ThreadLocal线程局部变量
在刚开始接触ThreadLocal,很难理解这个线程局部变量的使用场景。当现在回过头去看,ThreadLocal是一种多线程间并发访问变量的解决方案。与synchronized等加锁的方式不同,ThreadLocal完全不提供锁,而使用了以空间换时间的手段,为每个线程提供变量的独立副本,以保障线程安全,因此它不是一种数据共享的解决方案。
ThreadLocal是解决线程安全问题一个很好的思路,ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本,由于Key值不可重复,每一个“线程对象”对应线程的“变量副本”,而到达了线程安全。 特别值得注意的地方,从性能上说,ThreadLocal并不具有绝对的优势,在并发量不是很高时,也行加锁的性能会更好。但作为一套与锁完全无关的线程安全解决方案,在高并发量或者所竞争激烈的场合,使用ThreadLocal可以在一定程度上减少锁竞争。 下面是一个ThreadLocal的简单使用:
输出结果: