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对象)。ThreadLocalMap以ThreadLocal对象为Key,以你要保留的变量副本为Value。以获取值为例,ThreadLocal的get方法,首先通过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方法 ----------------------------------
由运行结果可以看出,由于使用了ThreadLocal,main线程和Thread-0线程之间并没有共享变量。
参考文章:
http://wenku.baidu.com/view/944d8f6327d3240c8447ef3a.html
相关推荐
ThreadLocal应用示例及理解,这个写了相关的示例,可以参考一下。
问题背景在 Tomcat 中,下面的代码都在 webapp 内,会导致 WebappClassLoaderWebappClassLoader 泄漏,无法被回收。
java 简单的ThreadLocal示例
JDBC事务的封装和Threadlocal实例,参考博客:http://blog.csdn.net/daijin888888/article/details/50988053
主要介绍了深入理解ThreadLocal工作原理及使用示例,涉及ThreadLocal<T> 简介和使用示例及ThreadLocal的原理等相关内容,具有一定参考价值,需要的朋友可以了解下。
主要介绍ThreadLocal的原理,实例分析以及注意事项
我们可以看到,通过这段代码实例化了一个ThreadLocal对象。我们只需要实例化对象一次,并且也不需要知道它是被哪个线程实例化。虽然所有的线程都能访问到这个ThreadLocal实例,但是每个线程却只能访问到自己通过调用...
主要介绍了Android 中 ThreadLocal使用示例的相关资料,这里提供示例代码帮助大家学习理解这部分内容,需要的朋友可以参考下
主要介绍了Java ThreadLocal用法,结合实例形式详细分析了ThreadLocal线程局部变量相关原理、定义与使用方法,需要的朋友可以参考下
ThreadLocalMap是ThreadLocal类中的内部类,实例却被Thread类持有,相当于每个线程持有一个map
ThreadLocal保证一个类的实例变量在各个线程中都有一份单独的拷贝, 从而不会影响其他线程中的实例变量
主要介绍了java 中ThreadLocal实例分析的相关资料,需要的朋友可以参考下
主要介绍了JAVA开发常用类库UUID、Optional、ThreadLocal、TimerTask、Base64使用方法与实例详解,需要的朋友可以参考下
主要介绍了Java 并发编程之ThreadLocal详解及实例的相关资料,需要的朋友可以参考下
主要介绍了从面试中的问题分析ThreadLocal,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,下面我们来一起学习一下吧
一篇文章我们来分析一个Java中ThreadLocal内存泄露的案例。分析问题的过程比结果更重要,理论结合实际才能彻底分析出内存泄漏的原因。
主要介绍了面试题ThreadLocal,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
主要介绍了java 中ThreadLocal 的正确用法的相关资料,需要的朋友可以参考下
ThreadLocal使用代码示例: public class MyThreadLocalTest { private ThreadLocal threadLocal=new ThreadLocal(){ @Override protected Integer initialValue() { return 1; } }; public void ...