ThreadLocal在1.6版本中不是用一个全局的Map来存各个线程的变量副本,而是在Thread类中有一个ThreadLocalMap的变量,然后用Thread.currentThread().threadLocals.get(this)来引用的各线程变量副本,这样避免了去同步全局的Map
ThreadLocal使用的简单例子:
package com.test; public class TestNum { // ①通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值 private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() { public Integer initialValue() { return 0; } }; // ②获取下一个序列值 public int getNextNum() { seqNum.set(seqNum.get() + 1); return seqNum.get(); } public static void main(String[] args) { TestNum sn = new TestNum(); // ③ 3个线程共享sn,各自产生序列号 TestClient t1 = new TestClient(sn); TestClient t2 = new TestClient(sn); TestClient t3 = new TestClient(sn); t1.start(); t2.start(); t3.start(); } private static class TestClient extends Thread { private TestNum sn; public TestClient(TestNum sn) { this.sn = sn; } public void run() { for (int i = 0; i < 3; i++) { // ④每个线程打出3个序列值 System.out.println("thread[" + Thread.currentThread().getName() + "] --> sn[" + sn.getNextNum() + "]"); } } } }
通常我们通过匿名内部类的方式定义ThreadLocal的子类,提供初始的变量值,如例子中①处所示。TestClient线程产生一组序列号,在③处,我们生成3个TestClient,它们共享同一个TestNum实例。运行以上代码,在控制台上输出以下的结果:
thread[Thread-0] --> sn[1]
thread[Thread-1] --> sn[1]
thread[Thread-2] --> sn[1]
thread[Thread-1] --> sn[2]
thread[Thread-0] --> sn[2]
thread[Thread-1] --> sn[3]
thread[Thread-2] --> sn[2]
thread[Thread-0] --> sn[3]
thread[Thread-2] --> sn[3]
考察输出的结果信息,我们发现每个线程所产生的序号虽然都共享同一个TestNum实例,但它们并没有发生相互干扰的情况,而是各自产生独立的序列号,这是因为我们通过ThreadLocal为每一个线程提供了单独的副本。
上面例子中,是在自己的类中定义ThreadLocal,那么,那么,可否直接使用Thread.currentThread().threadLocals?
不可以的,因为threadLocals变量在Thread中时package的访问权限,只能在同一个包下访问。
但是可以通过反射来得到threadLocals中的内容,参考:
http://stackoverflow.com/questions/2001353/java-list-thread-locals
threadLocals 是干什么用的?
是线程存放多个ThreadLocal实例的。
ThreadLocal首先通过当前线程t得到threadLocals,然后把自身this作为key,从threadLocals中得到存储在线程本地的相关的数据
ThreadLocal中get 和set方法如下:
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
其中 getMap方法简单如下:
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
总结ThreadLocal原理:ThreadLocal对象相当于线程私有财产(数据)的经纪人,为线程的私有财产(数据)提供存储和获取的代理功能,而私有财产存在Thread的ThreadLocalMap对象中
一个 ThreadLocal对象只对应一个值对象 ,多个ThreadLocal对象和相应的值存在线程中类型为ThreadLocalMap类型的threadLocals变量中
因为通常把多了属性封装在一个Map,而一个 ThreadLocal对象只对应这个map,但map存有多值,故会给人1个Threadlocal对应多个对象的错误印象
相关推荐
ThreadLocal原理及在多层架构中的应用
ThreadLocal的基本原理,核心机制,源码,ThreadLocal在分布式架构中的应用,ThreadLocal在基础架构,开源中间件,使用非常广泛,建议掌握。
面试过程中他问了ThreadLocal原理(上次问线程池,这次问ThreadLocal,美团爸爸这么喜欢线程安全机制么),今天详细讲一讲ThreadLocal原理。 ThreadLocal ThreadLocal是线程的内部存储类,可以在指定线程内存储数据...
主要介绍ThreadLocal的原理,实例分析以及注意事项
NULL 博文链接:https://bbsanwei.iteye.com/blog/778498
JDBC事务的封装和Threadlocal实例,参考博客:http://blog.csdn.net/daijin888888/article/details/50988053
详解java底层实现原理,ThreadLocal底层实现的数据结构,为什么不会导致内存泄露
ThreadLocal入门教程。 讲解了线程安全和ThreadLocal的使用的基本知识。
主要介绍了ThreadLocal原理及内存泄漏原因,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
通过ThreadLocal对象定位到线程:Thread.currentThread()通过ThreadLocal对象拿到所在的ThreadLocalMap: T
ThreadLocal
Java中ThreadLocal的设计与使用.doc
ThreadLocalMap是ThreadLocal类中的内部类,实例却被Thread类持有,相当于每个线程持有一个map
NULL 博文链接:https://bijian1013.iteye.com/blog/2380233
学习ThreadLocal,了解其中的原理,以及学习其中的优点!避免坑点!!
ThreadLocal的原理,源码深度分析及使用.docx,这是一份ThreadLocal的技术文档