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 类是线程类,在这个类中存在一个 threadLocals 变量,具体的类型是 ThreadLocal.ThreadLocalMap。 五、ThreadLocal 如何实现 set 方法 set 方法的实现非常重要,它的实现过程如下: 1. 获取当前线程...
这个功能是通过 Thread 类中的 threadLocals 属性来实现的,这个属性实际上是一个 Entry 数组,其中的每个 Entry 都是一个弱引用,易于在 GC 时被回收。 ThreadLocal 的工作机制是通过计算Hash值来确定在数组中的...
Thread类是Java线程的基类,每个线程都有一个ThreadLocalMap实例,这是通过Thread类中的threadLocals字段实现的。当ThreadLocal的get()或set()方法被调用时,会检查当前线程的ThreadLocalMap,如果不存在,就会创建...
ThreadLocal中包含一个ThreadLocalMap静态内部类,每个线程拥有一个ThreadLocalMap实例变量threadLocals,当调用set()、get()、remove()方法时,ThreadLocal通过当前线程对象获取对应的threadLocals对象,然后进行...
- 在`ThreadLocal`的`get()`方法中,首先通过`Thread.currentThread().threadLocals`获取到当前线程的`ThreadLocalMap`,然后根据`this`(即当前的ThreadLocal实例)作为键查找值。 - `set()`方法中,首先检查`...
3. `getMap(Thread t)`方法返回`t.threadLocals`,这是一个`ThreadLocalMap`实例,存储在线程的实例字段中。 4. `createMap(Thread t, T firstValue)`方法创建新的`ThreadLocalMap`并将第一个键值对插入其中,键为`...
- `ThreadLocal`类在`java.lang`包下,它的实现主要依赖于`Thread`类的成员变量`threadLocals`,这是一个`ThreadLocalMap`实例,`ThreadLocalMap`是`WeakReference<ThreadLocal<?>>`和`Object`(代表值)的键值对...
7. ThreadLocal的ThreadLocalMap:Thread类有属性变量threadLocals(类型是ThreadLocal.ThreadLocalMap),也就是说每个线程有一个自己的ThreadLocalMap。这样,每个线程往这个ThreadLocal中读写隔离的,并且是互相...
这个映射存储在线程的成员变量threadLocals中。由于ThreadLocalMap的设计,ThreadLocal变量在没有被显式清理的情况下,可能会导致内存泄漏,因为线程可能长时间运行,而ThreadLocal对象已经不再使用,但仍然保留在...
多线程示例####1.1 ThreadLocals + ThreadPools 该模块通过确保在 Runnable 执行结束时删除 ThreadLocal 上下文来测试内存泄漏保护####1.2。 分叉和加入本模块用于测试 Fork And Join ####1.3。 通过 RMI 使用信号...
1. **ThreadLocalMap**:每个`Thread`对象都有一个`threadLocals`字段,引用着一个`ThreadLocalMap`实例,这个Map用于存储每个线程的`ThreadLocal`变量及其对应的值。 2. **Entry**:`ThreadLocalMap`的内部类`...