ThreadLocal<T> Java线程局部变量
在 IBM XML,FORTRAN 等语言中在语法层面就提供了线程局部变量,但是Java在语法层面并没有提供这样的支持,而是在 JDK 1.2 开始就提供了 java.lang.ThreadLocal (并在JDK1.5开始支持泛型 ThreadLoca<T> )用于支持线程局部变量 ,使用ThreadLocal 工具类可以很简洁地编写多线程层程序,而不用像传统的方法那样编写大量的 Thread 同步块;
TheadLocal 不是一个线程,而是保存线程本地化对象的容器,当运行于多线程环境的某个对象使用 ThreadLocal 维护变量时,ThreadLocal 为每个使用该白能量的线程分配一个变量副本,每一个线程可以独立地改变自己的副本,而不会影响其他线程的副本;
ThreadLocal 提供的接口方法
ThreadLocal 包括以下4个接口,在实现一个线程局部变量类时可以实现以下的部分接口方法:
void set(Object value) | 设置当前线程的局部变量的值 |
public Object get() | 返回当前线程的局部变量的值 |
public void remove() | 当当前局部变量删除时执行的方法,目的是为了减少内存占用; |
public Object initialValue() | 返回当前线程的局部变量的初始值; |
一个 ThreadLocal 实例
以下示例用过 ThradLocal 实现局部变量:
public class SequenceNumber {
//线程局部变量,匿名实现 initValue() 方法
privatestatic ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>(){
public Integer initialValue(){
return 0;
}
};
publicint getNextNum(){
seqNum.set(seqNum.get() + 1);
return seqNum.get();
}
publicstatic void main(String[] args){
SequenceNumber sn = new SequenceNumber();
TestClient t1 = new TestClient(sn);
TestClient t2 = new TestClient(sn);
TestClient t3 = new TestClient(sn);
t1.start();
t2.start();
t3.start();
}
publicstatic class TestClient extends Thread{
private SequenceNumber sn;
public TestClient(SequenceNumber sn){
this.sn = sn;
}
public void run(){
for(int i=0;i<3;i++)
System.out.println("[Thread-"+Thread.currentThread().getName()+"]sn [" + sn.getNextNum() + "] ");
}
}
}
执行的结果如下,可以发现每个线程产生的序号虽然共享同一个 SequenceNumber 实例,但是它们并没有相互干扰,而是各自产生独立的序号;
[Thread-Thread-0] sn [1]
[Thread-Thread-0] sn [2]
[Thread-Thread-0] sn [3]
[Thread-Thread-2] sn [1]
[Thread-Thread-2] sn [2]
[Thread-Thread-2] sn [3]
[Thread-Thread-1] sn [1]
[Thread-Thread-1] sn [2]
[Thread-Thread-1] sn [3]
ThreadLocal 和Thread 同步机制的比较
对于多线程的资源同步问题,传统的 Thread 同步机制 和ThreadLocal 所采用的策略是不同的;
Thread 同步机制采用 “时间换空间” 的方式,实行访问串行化、对象共享化,多个线程共享一个对象,以线程竞争的方式争夺对象资源;
ThreadLocal 采用 “空间换时间” 的方式,实行访问并行化、对象独占化,为每一个线程提供一份变量拷贝,可以同时访问而互不影响;