线程级变量的理解和使用-ThreadLocal

1、概念
早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal很容易让人望文生义,想当然地认为是一个“本地线程”。其实,ThreadLocal并不是一个Thread,而是Thread的局部变量,也许把它命名为ThreadLocalVariable更容易让人理解一些。

当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。

2、原理

ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本。我们自己就可以提供一个简单的实现版本:

代码清单1 SimpleThreadLocal,仅仅实现set,get方法做示例, 它和JDK所提供的ThreadLocal类在实现思路上是相近的

Java代码 复制代码 收藏代码
  1. public class SimpleThreadLocal {
  2. private Map valueMap = Collections.synchronizedMap(new HashMap());
  3. public void set(Object newValue) {
  4. valueMap.put(Thread.currentThread(), newValue);①键为线程对象,值为本线程的变量副本
  5. }
  6. public Object get() {
  7. Thread currentThread = Thread.currentThread();
  8. Object o = valueMap.get(currentThread);②返回本线程对应的变量
  9. if (o == null && !valueMap.containsKey(currentThread)) {③如果在Map中不存在,放到Map
  10. 中保存起来。
  11. o = initialValue();
  12. valueMap.put(currentThread, o);
  13. }
  14. return o;
  15. }
  16. }

解释

总之,ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了保持对象的方法和避免参数传递的方便的对象访问方式。归纳了两点:
1。每个线程中都有一个自己的ThreadLocalMap类对象,可以将线程自己的对象保持到其中,各管各的,线程可以正确的访问到自己的对象。
2。将一个共用的ThreadLocal静态实例作为key,将不同对象的引用保存到不同线程的ThreadLocalMap中,然后在线程执行的各处通过这个静态ThreadLocal实例的get()方法取得自己线程保存的那个对象,避免了将这个对象作为参数传递的麻烦。
简单来说,当你的一个线程需要经过很多个对象处理时,每个对象都需要使用到同一个变量,1个做法就是不停的传递该变量。另1做发就是使用ThreadLocal,把这个变量作为线程级的变量。
请看示例代码:
Java代码 复制代码 收藏代码
  1. public class TestThreadLocal {
  2. static ThreadLocal tl1 = new ThreadLocal();
  3. class TLocal1 implements Runnable{
  4. void init() {
  5. tl1.set(new Object());
  6. }
  7. /* (non-Javadoc)
  8. * @see java.lang.Runnable#run()
  9. */
  10. @Override
  11. public void run() {
  12. init();
  13. try {
  14. Thread.sleep(1000);//暂停1秒,第2个线程应该也执行过init了吧
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. System.out.println(Thread.currentThread().getName() + " run:" + tl1.get());
  19. new TLocal2().print();
  20. }
  21. }
  22. class TLocal2 {
  23. public void print(){
  24. System.out.println(Thread.currentThread().getName() + " print:" + tl1.get());
  25. }
  26. }
  27. public static void main(String[] arg0) {
  28. TestThreadLocal test = new TestThreadLocal();
  29. Thread t1 = new Thread(test.new TLocal1(), "t1");
  30. Thread t2 = new Thread(test.new TLocal1(), "t2");
  31. t1.start();
  32. t2.start();
  33. }
  34. }

运行结果:同一个线程里,得到的总司本线程里的对象
t1 run:java.lang.Object@10b30a7
t2 run:java.lang.Object@1b67f74
t1 print:java.lang.Object@10b30a7
t2 print:java.lang.Object@1b67f74
posted on 2013-02-09 11:32  蜜雪薇琪  阅读(480)  评论(0编辑  收藏  举报