实例讲解Java并发编程之ThreadLocal类
ThreadLocal类可以理解为ThreadLocalVariable(线程局部变量),提供了get与set等访问接口或方法,这些方法为每个使用该变量的线程都存有一份独立的副本,因此get总是返回当前执行线程在调用set时设置的最新值。可以将ThreadLocal<T>视为包含了Map<Thread,T>对象,保存了特定于该线程的值。
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
模拟ThreadLocal
importjava.util.Collections;
importjava.util.HashMap;
importjava.util.Map;
publicclassSimpleThreadLocal<T>{
privateMap<Thread,T>valueMap=Collections
.synchronizedMap(newHashMap<Thread,T>());
publicvoidset(TnewValue){
valueMap.put(Thread.currentThread(),newValue);//①键为线程对象,值为本线程的变量副本
}
publicTget(){
ThreadcurrentThread=Thread.currentThread();
To=valueMap.get(currentThread);//②返回本线程对应的变量
if(o==null&&!valueMap.containsKey(currentThread)){//③如果在Map中不存在,放到Map中保存起来。
o=initialValue();
valueMap.put(currentThread,o);
}
returno;
}
publicvoidremove(){
valueMap.remove(Thread.currentThread());
}
protectedTinitialValue(){
returnnull;
}
}
实用ThreadLocal
classCount{
privateSimpleThreadLocal<Integer>count=newSimpleThreadLocal<Integer>(){
@Override
protectedIntegerinitialValue(){
return0;
}
};
publicIntegerincrease(){
count.set(count.get()+1);
returncount.get();
}
}
classTestThreadimplementsRunnable{
privateCountcount;
publicTestThread(Countcount){
this.count=count;
}
@Override
publicvoidrun(){
//TODOAuto-generatedmethodstub
for(inti=1;i<=3;i++){
System.out.println(Thread.currentThread().getName()+"\t"+i
+"th\t"+count.increase());
}
}
}
publicclassTestThreadLocal{
publicstaticvoidmain(String[]args){
Countcount=newCount();
Threadt1=newThread(newTestThread(count));
Threadt2=newThread(newTestThread(count));
Threadt3=newThread(newTestThread(count));
Threadt4=newThread(newTestThread(count));
t1.start();
t2.start();
t3.start();
t4.start();
}
}
输出
Thread-0 1th 1 Thread-0 2th 2 Thread-0 3th 3 Thread-3 1th 1 Thread-1 1th 1 Thread-1 2th 2 Thread-2 1th 1 Thread-1 3th 3 Thread-3 2th 2 Thread-3 3th 3 Thread-2 2th 2 Thread-2 3th 3