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的基本概念、使用方法、生命周期管理和实际应用示例的详细解释。了解并熟练掌握ThreadLocal可以帮助我们编写出更高效、更安全的多线程代码。在Java并发编程中,ThreadLocal是一个不可或缺的...
at 中专门为每一个 web 应用实例创建的类加载器,它负责加载该 web 应用下的所有类。当 web 应用被卸载时,WebappClassLoader 本应随之被垃圾收集器回收。然而,如果存在对 WebappClassLoader 的强引用,那么这个类...
- **性能影响**:过度使用`ThreadLocal`可能导致额外的内存消耗和GC压力,因为每个线程都需要维护自己的变量副本。 - **代码可读性和可维护性**:`ThreadLocal`的使用可能使代码变得复杂,不易于理解和调试,尤其是...
在提供的"ThreadLocal示例"压缩包中,可能包含了一些具体的代码示例,展示如何在实际项目中运用ThreadLocal。通过查看这些示例,你可以更深入地理解ThreadLocal的工作方式以及如何在你的代码中有效地利用它。
在Java的数据库编程中,事务(Transaction)是确保数据一致性的重要机制。...通过使用ThreadLocal,我们可以创建线程安全的变量,使得每个线程都能拥有独立的数据库连接和事务管理,避免了潜在的并发问题。
#### 五、Java API中的ThreadLocal示例 下面的示例展示了一个更具体的场景——为每个线程分配一个唯一的标识符。 ```java import java.util.concurrent.atomic.AtomicInteger; public class ThreadId { // ...
理解ThreadLocal的工作原理和使用方法对于编写高效、安全的多线程程序至关重要。 ### ThreadLocal简介 ThreadLocal并非一个线程对象,而是一个线程局部变量的容器。每个线程都有自己的ThreadLocal实例,它们各自...
**标题:“JDK的ThreadLocal理解(一)使用和测试”** **正文:** ThreadLocal是Java中的一个非常重要的线程安全工具类,它在多线程编程中扮演着独特的角色。通过创建ThreadLocal实例,我们可以为每个线程提供一个...
本篇文章将聚焦于Spring事务处理中ThreadLocal的使用,以及如何通过源码理解和应用这个工具。 首先,了解Spring事务管理的基本概念。在多线程环境中,事务管理是至关重要的,它负责确保一组数据库操作要么全部成功...
本文将深入探讨ThreadLocal的使用以及Spring框架中的事务管理,这两个主题都是Java开发人员必须掌握的关键技能。 首先,让我们了解ThreadLocal。ThreadLocal是Java提供的一种线程绑定变量的工具类,它允许我们在一...
ThreadLocal简介和使用示例 ThreadLocal只有一个无参的构造方法public ThreadLocal(),它的相关方法包括: * public T get():获取当前线程的变量副本 * public void set(T value):设置当前线程的变量副本 * ...
当线程使用ThreadLocal时,它会查找或创建属于该线程的变量实例,而不是所有线程共享一个实例。 误区二:ThreadLocal与每个session相对应 在Java Web编程中,ThreadLocal与HTTP Session的概念混淆是常见的误解。...
下面是一个简单的`ThreadLocal`使用示例: ```java public class ThreadLocalDemo { public static void main(String[] args) { ThreadLocal<String> threadLocal = new ThreadLocal(); // 在主线程中设置值 ...
在Java编程领域,ThreadLocal和事务管理是两个关键的概念,特别是在构建复杂且高效的Web应用程序时。ThreadLocal是一种线程局部变量,而事务则是数据库操作的原子性保证。在这个小型简单练习中,我们看到如何结合c3p...
ThreadLocal内部使用了一个ThreadLocalMap,它是一个基于ThreadLocal实例作为键,值为用户存储对象的弱引用表。每个线程都有一个这样的ThreadLocalMap,保证了线程间数据的隔离。 6. **工具支持** 在实际开发中,...
ThreadLocal的使用方法是创建一个ThreadLocal实例,然后通过其set()方法设置线程局部变量,get()方法获取当前线程的该变量值。需要注意的是,ThreadLocal不是线程安全的,它只是保证了线程内部的隔离性,但不负责...
### 正确理解ThreadLocal:深入解析其工作原理与应用场景 #### 一、ThreadLocal的基本...因此,在使用`ThreadLocal`时,应当充分理解其工作机制,合理规划其生命周期,并适时进行资源清理,以确保系统的稳定性和性能。
Java线程编程中的ThreadLocal类是一个非常重要的工具,它在多线程环境下提供了一种线程局部变量的机制。ThreadLocal并非是简单的变量,...正确理解和使用ThreadLocal,能够帮助我们编写出更加健壮、高效的并发程序。