一、概述
ThreadLocal的名称比较容易让人误解,会认为其是一个“本地线程”。其实,ThreadLocal并不是一个Thread,而是Thread的局部变量。
其设计的初衷是为了解决多线程编程中的资源共享问题。提起这个,大家一般会想到synchronized,synchronized采取的是“以时间换空间”的策略,本质上是对关键资源上锁,让大家排队操作。而ThreadLocal采取的是“以空间换时间”的思路,为每个使用该变量的线程提供独立的变量副本,在本线程内部,它相当于一个“全局变量”,可以保证本线程任何时间操纵的都是同一个对象。
二、实例
下面用一个实例阐述ThreadLocal的使用方法
创建一个Context类,其中含有transactionId属性。
1 package com.vigar;
2
3 public class Context {
4
5 private String transactionId = null;
6
7 public String getTransactionId() {
8 return transactionId;
9 }
10
11 public void setTransactionId(String transactionId) {
12 this.transactionId = transactionId;
13 }
14 }
创建MyThreadLocal做为容器,将一个Context对象保存于ThreadLocal中
1 package com.vigar;
2
3 public class MyThreadLocal {
4 public static final ThreadLocal userThreadLocal = new ThreadLocal();
5 public static void set(Context user) {
6 userThreadLocal.set(user);
7 }
8
9 public static void unset() {
10 userThreadLocal.remove();
11 }
12
13 public static Context get() {
14 return (Context)userThreadLocal.get();
15 }
16 }
多线程客户端程序,用于测试
1 package com.vigar;
2
3 import java.util.Random;
4
5 public class ThreadLocalDemo extends Thread {
6
7 public static void main(String[] args) {
8 Thread threadOne = new ThreadLocalDemo();
9 threadOne.start();
10 Thread threadTwo = new ThreadLocalDemo();
11 threadTwo.start();
12 }
13
14 @Override
15 public void run() {
16 // 线程
17 Context context = new Context();
18 Random random = new Random();
19 int age = random.nextInt(100);
20 context.setTransactionId(String.valueOf(age));
21
22 System.out.println("set thread ["+getName()+"] contextid to " + String.valueOf(age));
23 // 在ThreadLocal中设置context
24 MyThreadLocal.set(context);
25 /* note that we are not explicitly passing the transaction id */
26 try {
27 Thread.sleep(1000);
28 } catch (InterruptedException e)
29 {
30 e.printStackTrace();
31 }
32
33 new BusinessService().businessMethod();
34 MyThreadLocal.unset();
35 }
36 }
模拟业务层,在某处读取context对象
1 package com.vigar;
2 public class BusinessService {
3 public void businessMethod() {
4 Context context = MyThreadLocal.get();
5 System.out.println(context.getTransactionId());
6 }
7 }
程序输出:
set thread [Thread-0] contextid to 32
set thread [Thread-1] contextid to 89
32
89
三、总结
ThreadLocal使用步骤
1.建立ThreadLocal容器对象A,其中对需要保存的属性进行封装。并提供相应的get/set方法(全部为static)
2.在客户端程序中,用A.setxxx, A.getXXX访问相应数据,即可保证每个线程访问的是自己独立的变量
参考文献:
1. http://lavasoft.blog.51cto.com/62575/51926/
2. http://veerasundar.com/blog/2010/11/java-thread-local-how-to-use-and-code-sample/