6.ThreadLocal类及应用技巧
1 import java.util.Random; 2 3 /** 4 * ThreadLocal类及应用技巧 5 * ******************************************************************* 6 * 每个线程调用全局ThreadLocal对象的set方法,就相当于往其内部的map中增加一条记录,key 7 * 分别是各自的线程,values是各自的set方法穿进去的值。在线程结束时可以调用ThreadLocal.clear(); 8 * 方法,这样会更快释放内存,不调用也可以,因为线程结束后也可以自动释放相关的ThreadLocal变量。 9 * 实现对ThreadLocal变量的封装,让外界不要直接操作ThreadLocal变量 10 * 对基本类型的数据的封装,这种应用相对少见。 11 * 对对象类型的数据的封装,比较常见,即让某个类针对不同线程分别创建一个独立的实例对象。 12 * 总结: 13 * 一个ThreadLocal代表一个变量,故其中里只能放一个数据,你有两个变量都要线程范围内 14 * 共享,则要定义两个ThreadLocal对象。如果有一百个变量要线程共享呢?把ThreadLocal封装 15 * 到一个单例类中。 16 * 17 * Struts2中的思想就是ThreadLocal模式 18 * 19 * ******************************************************************* 20 * 虚拟机挂掉的时候注册钩子通知 21 * Runtime->addShutdownHook(Thread hook) 22 * @author LiTaiQing 23 */ 24 public class ThreadLocalTest { 25 private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(); 26 //private static ThreadLocal<MyThreadScopeData> myThreadScopeData = new ThreadLocal<MyThreadScopeData>(); 27 public static void main(String[] args){ 28 for(int i = 0; i < 2 ; i++){ 29 new Thread(new Runnable(){ 30 @Override 31 public void run() { 32 int data = new Random().nextInt(); 33 System.out.println(Thread.currentThread().getName() + " get put data :" + data); 34 threadLocal.set(data); 35 //myThreadScopeData.set(new MyThreadScopeData("name"+data,data)); 36 MyThreadScopeData.getThreadInstance().setName("name" + data); 37 MyThreadScopeData.getThreadInstance().setAge(data); 38 new A().get(); 39 new B().get(); 40 } 41 }).start(); 42 } 43 } 44 static class A{ 45 public void get(){ 46 int data = threadLocal.get(); 47 System.out.println("A from" + Thread.currentThread().getName() + " get put data :" + data); 48 //MyThreadScopeData myData = myThreadScopeData.get(); 49 MyThreadScopeData myData = MyThreadScopeData.getThreadInstance(); 50 System.out.println("A from" + Thread.currentThread().getName() + " getMyData :" + myData.getName()+","+myData.getAge()); 51 } 52 } 53 static class B{ 54 public void get(){ 55 int data = threadLocal.get(); 56 System.out.println("B from" + Thread.currentThread().getName() + " get put data :" + data); 57 //MyThreadScopeData myData = myThreadScopeData.get(); 58 MyThreadScopeData myData = MyThreadScopeData.getThreadInstance(); 59 System.out.println("B from" + Thread.currentThread().getName() + " getMyData :" + myData.getName()+","+myData.getAge()); 60 } 61 } 62 } 63 class MyThreadScopeData{ 64 private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>(); 65 //private static MyThreadScopeData instance = null;//new MyThreadScopeData(); 66 67 private MyThreadScopeData(){}; 68 /** 69 * 这里可以不用synchronized,因为位于不同的线程内分别保存在ThreadLocal中 70 * @return 71 */ 72 public static /*synchronized*/ MyThreadScopeData getThreadInstance(){ 73 MyThreadScopeData instance = map.get(); 74 //这种方式容易出现多线程并发问题。所以最好采用饿汉模式 75 if(instance==null){ 76 instance = new MyThreadScopeData(); 77 map.set(instance); 78 } 79 return instance; 80 } 81 82 private String name; 83 private int age; 84 85 // public MyThreadScopeData(String name, int age) { 86 // super(); 87 // this.name = name; 88 // this.age = age; 89 // } 90 public String getName() { 91 return name; 92 } 93 public void setName(String name) { 94 this.name = name; 95 } 96 public int getAge() { 97 return age; 98 } 99 public void setAge(int age) { 100 this.age = age; 101 } 102 }