jclown

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  3 Posts :: 0 Stories :: 6 Comments :: 0 Trackbacks

      ThreadLocal是线程变量的意思,不是本地线程。它可以为线程分配特有的空间(与线程自身的堆栈不同,是线程对象在内存中的一个Map),使得线程可以通过这个空间随时获取自己相关的上下文信息。

ThreadLocal 内幕

ThreadLocal很容易让使用者误解(以前我就误解了),因为在这个类中定义了一个静态的包级可见的内部类ThreadLocalMap,同时ThreadLocal对外提供了get和set方法。那么set的时候就是把当前线程对象作为ThreadLocalMap的key,把传入set方法的值作为value存储起来;get的时候通过获取当前线程对象,然后到ThreadLocalMap中取得对应的value。这种认识是表面的很容易理解的方式,但是也是错误的理解。

每个Thread类中都有ThreadLocal.ThreadLocalMap的两个成员,分别是threadlocals与inheritableThreadLocals。前者用来存储当前线程的相关数据信息,后者用来存储从父线程中继承或者说拷贝过来的相关数据信息。这两个区域也就是前面提到的线程的特别存储区域,但是如何操作它们?JDK中的设计并不是让用户直接操作当前线程来存取数据,而是让用户操作ThreadLocal来对当前线程的这两个Map进行存取(个人认为这样设计是出于安全性与易用性考虑,主要是Map中的key值需要固定才能取到同一对象),同时放置在这两个Map中的key值就是ThreadLocal对象自身,value由用户传入。


ThreadLocal 进阶

ThreadLocal为线程独占某些对象或者资源提供了新的手段,ThreadLocal与线程堆栈都是用来存取线程私有数据的区域,别的线程无法触碰这两个区域,但是二者确有不同的生命周期。这个可以这样理解,线程跨多个方法调用的时候,方法作为Frame不断的进栈和出栈(方法的调用与返回),同时出栈的时候方法中的临时变量数据会被回收,在这个线程的堆栈中消失,所以方法中的局部变量是无法在线程调用过程中穿透,除非是传递局部的引用类型变量,但是这也意味着方法接口都要额外接收新的参数(早期系统中传递JDBC数据库连接的方式)。而ThreadLocal不同,准确地说是线程中的ThreadLocalMap不同,线程对象中的ThreadLocalMap对象是伴随整个线程对象生命周期的,线程可以在任何需要的时候通过它来获取相关数据,这为线程独占数据提供了一种更加优雅的方式。只不过这一切都是通过ThreadLocal来操作的而已,同时ThreadLocal自身也作为不同线程中的ThreadLocalMap中的key来映射存入的value。

ThreadLocal 应用

public class ThreadWriter

{

   private static final ThreadLocal<FileWriter> local = new

ThreadLocal<FileWriter>();

    public void write(String s)

    {

       try

       {

           getFileWriter().write(s);

       }

       catch(IOException e)

       {

           //igore

       }

    }

    private FileWriter getFileWriter()

    {

       FileWriter fw = local.get();

       if (null == fw)

       {

           try

           {

fw = new FileWriter(Thread.currentThread().getName() + "-info.txt", true);

              local.set(fw);

           }

           catch(IOException e)

           {

             //igore

           }

       }

       return fw;

    }

}

这里说明几个问题:

1、 ThreadLocal对象只有一份,它将作为不同线程中的ThreadLocalMap对象的key,所映射的值是不同文件路径的FileWriter对象。只不过不同 线程中的ThreadLocalMap中的key值都一样,但是因为在不同的ThreadLocalMap中,不会有任何影响,反而这样的方式为每个线程中ThreadLocalMap对象中的key值生成省去了很多功夫,这是一个很精妙的设计,用户在间接使用ThreadLocalMap的时候,不需要感知key是什么,就可以方便地存取。

2、 一份ThreadLocal对象只能映射一种资源。如需要映射多种资源的话,定义多个ThreadLocal成员。

3、 local.set(fw); 这句代码表示将local自身作为key,fw作为value,存储在调用这行代码的线程中的ThreadLocalMap对象中。

FileWriter fw = local.get(); 这句代码表示将local自身作为key,从当前线程的ThreadLocalMap对象中取出属于自己独占的FileWriter对象。 

posted on 2010-09-19 20:06 jclown 阅读(2206) 评论(2)  编辑  收藏 所属分类: Java 杂谈

Feedback

# re: 理解 ThreadLocal 2010-09-21 12:35 Chase
不错不错,这个又让我加深了对  回复  更多评论
  

# re: 理解 ThreadLocal[未登录] 2010-09-24 19:31 steven
我是这样理解的. 不知道对不对.
某个类需要为每一个访问的线程都提供一份实例,他需要把这份实例保存在ThreadLocal里面, 可供线程上下文可以随时访问这个实例.  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: