本篇文章为大家展示了使用ThreadLocal的作用有哪些,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。
ThreadLocal,直译为“线程本地”或“本地线程”,如果你真的这么认为,那就错了!其实,它就是一个容器,用于存放线程的局部变量,我认为应该叫做ThreadLocalVariable(线程局部变量)才对,真不理解为什么当初,Sun 公司的工程师这样命名。
早在JDK 1.2的时代,. lang。ThreadLocal就诞生了,它是为了解决多线程并发问题而设计的,只不过设计得有些难用,所以至
今没有得到广泛使用。其实它还是挺有用的,不相信的话,我们一起来看看这个例子吧。
一个序列号生成器的程序,可能同时会有多个线程并发访问它,要保证每个线程得到的序列号都是自增的,而不能相互干扰。
先定义一个接口:
public interface Sequence { ,int getNumber (); }
每次调用getNumber()方法可获取一个序列号,下次再调用时,序列号会自增。
再做一个线程类:
public class ClientThread extends Thread { ,private Sequence 序列; ,public ClientThread (Sequence 序列),{ 时间=this.sequence 才能;序列; ,} ,@Override ,public void  run (), { for 才能;(int 小姐:=,0;,小姐:& lt;, 3;,我+ +),{ ,,System.out.println (Thread.currentThread () . getname(), +,,,=祝辞,“,+,sequence.getNumber ()); ,,} ,} }
在线程中连续输出三次线程名与其对应的序列号。
我们先不用ThreadLocal,来做一个实现类吧。
public class SequenceA implements Sequence { ,private static  int number =, 0; ,public int  getNumber (), { 时间=number 才能;number +, 1; return 才能;数量; ,} ,public static  void main (String [], args), { Sequence 才能;Sequence =, new SequenceA (); ClientThread 才能;thread1 =, new ClientThread(序列); ClientThread 才能;thread2 =, new ClientThread(序列); ClientThread 才能;thread3 =, new ClientThread(序列); thread1.start才能(); thread2.start才能(); thread3.start才能(); ,} }
序列号初始值是0,在主要()方法中模拟了三个线程,运行后结果如下:
Thread-0=比;1
Thread-0=比;2
Thread-0=比;3
线程2=比;4
线程2=比;5
线程2=比;6
线程1=比;7
线程1=比;8
线程1=比;9
由于线程启动顺序是随机的,所以并不是0,1,2这样的顺序,这个好理解。为什么当,Thread-0输出了1,2,3之后,而,线程2却输出了4、5、6呢?线程之间竟然共享了静态变量!这就是所谓的“非线程安全“问题了。
那么如何来保证”线程安全”呢?对应于这个案例,就是说不同的线程可拥有自己的静态变量,如何实现呢?下面看看另外一个实现吧。
public class SequenceB implements Sequence { ,private static  ThreadLocal(), { @Override才能 protected 才能;Integer  initialValue (), { ,,return 0; ,,} ,}; ,public int  getNumber (), { numberContainer.set才能(numberContainer.get (), +, 1); return 才能numberContainer.get (); ,} ,public static  void main (String [], args), { Sequence 才能;Sequence =, new SequenceB (); ClientThread 才能;thread1 =, new ClientThread(序列); ClientThread 才能;thread2 =, new ClientThread(序列); ClientThread 才能;thread3 =, new ClientThread(序列); thread1.start才能(); thread2.start才能(); thread3.start才能(); ,} }
通过,ThreadLocal封装了一个整数类型的,numberContainer静态成员变量,并且初始值是0。再看,getNumber()方法,首先从,numberContainer中得到出当前的值,加1,随后设置到,numberContainer中,最后将,numberContainer中得到出当前的值并返回。
是不是很恶心?但是很强大!确实稍微饶了一下,我们不妨把,ThreadLocal看成是一个容器,这样理解就简单了,所以,这里故意用容器这个单词作为后缀来命名ThreadLocal变量。