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 }