2、ThreadLocal
我们知道线程之所以不安全是因为线程之间存在竞争,而存在竞争是因为它们共享资源。因此有时候,我们会需要将资源只在本线程内,资源只与相应的线程存在关系,那么就避免了线程不安全。
ThreadLocal就是一个将变量与特定的线程进行绑定的一个类,资源只会属于一个特定的线程。
ThreadLocal就是一个Map,它的键就是线程,值是资源变量。
这样的话,ThreadLocal就可以看成是一个局部变量。
1 class MyTrehadData { 2 private static ThreadLocal<MyThreadData> threadLocal=new ThreadLocal<MyThreadData>(); 3 private int data; 4 private MyThreadData(){} 5 6 public static MyThread getLocalThread() { 7 MyThreadData instance=threadLocal.get(); 8 if(instance==null) { 9 instance=new MyThreadData(); 10 threadLocal.set(instance); 11 } 12 return instance; 13 } 14 15 public int getData() { 16 return data; 17 } 18 19 public void setData(int data) { 20 this.data=data 21 } 22 }
1 public class ThreadScopeShare { 4 public static void main(String[]args) { 5 new ThreadScopseShare().init(); 6 } 7 8 public void init() { 9 for(int i=0;i<2;i++) { 10 new Thread(new Runnable() { 11 public void run() { 12 MyThreadData myData=MyThreadData.getLocalThread(); 13 myData.setData(new Random().nextInt()); 14 System.out.println(Thread.currentThread().getName()+" set data:"+myData.getData());16 new A().get(); 17 new B().get(); 18 } 19 }); 20 } 21 } 22 23 class A { 24 public void get() { 25 MyThreadData myData=myThreadData.getLocalThread(); 26 System.out.println("A from "+Thread.currentThread().getName()+" get data:"+myData.getData()); 27 } 28 } 29 30 31 class B { 32 public void get() { 33 MyThreadData myData=myThreadData.getLocalThread(); 34 System.out.println("B from "+Thread.currentThread().getName()+" get data:"+myData.getData()); 35 } 36 }
在这里类MyThreadData是一个单例(当然不是严格意义上的单例),而且MyThreadData的属性ThreadLocal属于类所有,也就是说所有的线程都会是同一个ThreadLocal。只是ThreadLocal当中的空间
是与该线程相关的。
ThreadLocal类提供了get和set方法往这个容器当中取值和设置值。其实就是看哪个线程跑这段代码,那么就会根据这个线程的名字去设置或者取出它相应的值(根据线程名去进行操作这是一种隐性操作)。
于是,这个程序的含义就是:有两个线程1和2,它们都会往ThreadLocal当中放入相应的随机值。只是线程1放入随机值时,是以"Thread-1"作为键;线程2放入随机值时,是以"Thread-2"作为键。
当从ThreadLocal里面取值时,如果是线程1跑这段代码,那么就会以键"Thread-1"来取相应的值;反之如果是线程2来跑这段代码,那么就会以"Thread-2"来取相应的值。