欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ThreadLocal简介和使用示例

程序员文章站 2022-07-12 14:30:50
...

java.lang.ThreadLocal类的实例,为每一个使用该实例的线程提供一个变量的副本,在线程的内部共享这个副本,其他线程无法获取该线程的变量,这就好像该线程独立拥有该变量一样。

一、结构介绍

ThreadLocal类定义中有一个静态内部类(详见http://forestqqqq.iteye.com/blog/1906653),即ThreadLocalMap类。每一个线程(Thread)内部都有一个ThreadLocal.ThreadLocalMap对象,

 

public class Thread implements Runnable {
//……
ThreadLocal.ThreadLocalMap threadLocals = null;
//……
}

 

 

每一个ThreadLocalMap中保存了一个或多个ThreadLocal对象(因为可以在线程的不同地方定义ThreadLocal对象)。ThreadLocalMapThreadLocal对象为Key,以你要保留的变量副本为Value。以获取值为例,ThreadLocalget方法,首先通过Thread.currentThread().threadLocals的方式获取本线程的ThreadLocalMap对象,然后以this作为Key,取出之前保存的Value

二、重要方法

(1) public T get()

获取当前线程的本ThreadLocal对象(之前讲过了,由于Thread内有ThreadLocalMap属性的存在,ThreadLocal可以有很多个)对应的变量副本。

public T get() {
      //获取当前线程
        Thread t = Thread.currentThread();
      //获取当前线程的ThreadLocalMap对象,相当于t.threadLocals
        ThreadLocalMap map = getMap(t);
      //由本ThreadLocal的this对象为Key,获取已保存的变量副本
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
      //如果没找该ThreadLocal对象为Key的对应的副本,就调用setInitialValue()方法
      //经分析setInitialValue()方法源码可知,该方法将把initValue()方法的返回值作为自己的返回值返回,并且保留这个返回值到ThreadLocalMap中,以便下一次调用时可以直接从ThreadLocalMap中取值。
        return setInitialValue();
}

 

(2) public void set(T value)

value保存到本线程的ThreadLocalMap中去

public void set(T value) {
      //获取当前线程
        Thread t = Thread.currentThread();
//获取当前线程的ThreadLocalMap对象,相当于t.threadLocals
        ThreadLocalMap map = getMap(t);
//以ThreadLocal的this对象作为Key,参数value作为值,保存到当前线程的ThreadLocalMap中
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
}

 

(3) public void remove()

删除当前线程的本ThreadLocal对应的变量副本

public void remove() {
//获取当前线程的ThreadLocalMap对象,相当于Thread.currentThread().threadLocals
         ThreadLocalMap m = getMap(Thread.currentThread());
//以本ThreadLocal的this作为Key,去除对应的副本
         if (m != null)
             m.remove(this);
}

 

(4)protected T initValue()

在创建ThreadLocal对象之后,没有调用set方法之前,当你第一次调用get方法时,返回的值就是这个方法的返回值。而且这个返回值已经被保存到了当前线程的ThreadLocalMap属性中去了,下此调用时会直接返回该值。该方法是protected类型的,所以可以再子类中重写该方法(见:使用示例)。

protected T initialValue() {
        return null;
}

 

三、使用示例

public class ThreadLocalTest {
   public static TLTest1 test1 = new TLTest1();
   public static TLTest2 test2 = new TLTest2();
   public static TLTest3 test3 = new TLTest3();
   public static void main(String[] args) {
      test();
      new Thread(){
        public void run(){
           ThreadLocalTest.test();
           this.stop();
        }
      }.start();
   }
  
   public static void test(){
      System.out.println("++++++++++++++++++++++++++++++++");
      System.out.println("在调用set方法之前,调用get方法。输出如下:");
      System.out.println("test1=="+test1.toString());
      System.out.println("test2=="+test2.toString());
      System.out.println("test3=="+test3.toString());
      System.out.println("*****************************");
      System.out.println("调用set方法");
      test1.tl.set(true);
      test2.t2.set(999);
      test3.t3.set("调用了set方法");
      System.out.println("*****************************");
      System.out.println("重新输出:");
      System.out.println("test1=="+test1.toString());
      System.out.println("test2=="+test2.toString());
      System.out.println("test3=="+test3.toString());
      System.out.println("----------------------------------");
   }
 
}
 
class TLTest1{
   public ThreadLocal<Boolean> tl = new ThreadLocal<Boolean>();
   public String toString(){
      return "线程:"+Thread.currentThread().getName()+"=="+tl.get();
   }
}
 
class TLTest2{
   public ThreadLocal<Integer> t2 = new ThreadLocal<Integer>(){
      //重写initialValue()方法,如果不重写,返回的是null
      protected Integer initialValue(){
        return 1000;
      }
   };
   public String toString(){
      return  "线程:"+Thread.currentThread().getName()+"=="+t2.get().toString();
   }
}
 
class TLTest3{
   public ThreadLocal<String> t3 = new ThreadLocal<String>(){
      //在这里重写initialValue()方法,如果不重写,返回的是null
      protected String initialValue(){
        return "这就是我重写的一个方法!";
      }
   };
   public String toString(){
      return "线程:"+Thread.currentThread().getName()+"=="+t3.get().toString();
   }
}

 

 

运行结果:

++++++++++++++++++++++++++++++++
在调用set方法之前,调用get方法。输出如下:
test1==线程:main==null
test2==线程:main==1000
test3==线程:main==这就是我重写的一个方法!
*****************************
调用set方法
*****************************
重新输出:
test1==线程:main==true
test2==线程:main==999
test3==线程:main==调用了set方法
----------------------------------
++++++++++++++++++++++++++++++++
在调用set方法之前,调用get方法。输出如下:
test1==线程:Thread-0==null
test2==线程:Thread-0==1000
test3==线程:Thread-0==这就是我重写的一个方法!
*****************************
调用set方法
*****************************
重新输出:
test1==线程:Thread-0==true
test2==线程:Thread-0==999
test3==线程:Thread-0==调用了set方法
----------------------------------

 

 

由运行结果可以看出,由于使用了ThreadLocalmain线程和Thread-0线程之间并没有共享变量。

 

 

参考文章:

http://wenku.baidu.com/view/944d8f6327d3240c8447ef3a.html

http://blog.csdn.net/abing37/article/details/4460298

http://www.jcwcn.com/article-30276-1.html