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中。