Java 中ThreadLocal类详解
ThreadLocal类,代表一个线程局部变量,通过把数据放在ThreadLocal中,可以让每个线程创建一个该变量的副本。也可以看成是线程同步的另一种方式吧,通过为每个线程创建一个变量的线程本地副本,从而避免并发线程同时读写同一个变量资源时的冲突。
示例如下:
importjava.util.Random;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
importjava.util.concurrent.TimeUnit;
importcom.sun.javafx.webkit.Accessor;
publicclassThreadLocalTest{
staticclassThreadLocalVariableHolder{
privatestaticThreadLocal<Integer>value=newThreadLocal<Integer>(){
privateRandomrandom=newRandom();
protectedsynchronizedIntegerinitialValue(){
returnrandom.nextInt(10000);
}
};
publicstaticvoidincrement(){
value.set(value.get()+1);
}
publicstaticintget(){
returnvalue.get();
}
}
staticclassAccessorimplementsRunnable{
privatefinalintid;
publicAccessor(intid){
this.id=id;
}
@Override
publicvoidrun(){
while(!Thread.currentThread().isInterrupted()){
ThreadLocalVariableHolder.increment();
System.out.println(this);
Thread.yield();
}
}
@Override
publicStringtoString(){
return"#"+id+":"+ThreadLocalVariableHolder.get();
}
}
publicstaticvoidmain(String[]args){
ExecutorServiceexecutorService=Executors.newCachedThreadPool();
for(inti=0;i<5;i++){
executorService.execute(newAccessor(i));
}
try{
TimeUnit.MICROSECONDS.sleep(1);
}catch(InterruptedExceptione){
e.printStackTrace();
}
executorService.shutdownNow();
}
}
运行结果:
#1:9685 #1:9686 #2:138 #2:139 #2:140 #2:141 #0:5255 。。。
由运行结果可知,各线程都用于各自的Local变量,并各自读写互不干扰。
ThreadLocal共提供了三个方法来操作,set,get和remove。
在Android中的Looper,即使用了ThreadLocal来为每个线程都创建各自独立的Looper对象。
publicfinalclassLooper{
privatestaticfinalStringTAG="Looper";
//sThreadLocal.get()willreturnnullunlessyou'vecalledprepare().
staticfinalThreadLocal<Looper>sThreadLocal=newThreadLocal<Looper>();
privatestaticvoidprepare(booleanquitAllowed){
if(sThreadLocal.get()!=null){
thrownewRuntimeException("OnlyoneLoopermaybecreatedperthread");
}
sThreadLocal.set(newLooper(quitAllowed));
}
。。。
}
当某个线程需要自己的Looper及消息队列时,就调用Looper.prepare(),它会为线程创建属于线程的Looper对象及MessageQueue,并将Looper对象保存在ThreadLocal中。