详解Java中的ThreadLocal、ThreadLocalMap和Thread之间的关系
来源:互联网 发布:linux网络工程师 编辑:程序博客网 时间:2024/06/05 10:21
每个ThreadLocal实例都有一个唯一的threadLocalHashCode(这个值将会用于在ThreadLocalMap中找到ThreadLocal对应的value值),它是通过静态变量nextHashCode和HASH_INCREMENT进行计算的,其中nextHashCode 和HASH_INCREMENT 的定义如下
private static AtomicInteger nextHashCode = new AtomicInteger();
private static final int HASH_INCREMENT = 0x61c88647;
nextHashCode()方法如下
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
每个Thread中都有一个threadLocals字段,其定义如下:
ThreadLocal.ThreadLocalMap threadLocals = null;
这个字段在创建线程时为null,当调用ThreadLocal中的setInitialValue()和set(T value)方法时会创建ThreadLocalMap对象,这两个方法内部都是调用createMap方法
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
setInitialValue()方法中设置的firstValue值是通过initialValue()方法得到的,默认的initialValue()方法返回值是null,如下所示:
protected T initialValue() {
return null;
}
在我们自己使用时,因此通常需要override此方法。
ThreadLocalMap类中有一个静态内部类Entry,ThreadLocal实例和对应的值都是存放在entry元素中的,类定义如下:
static class Entry extends WeakReference<ThreadLocal> {
Object value;
Entry(ThreadLocal k, Object v) {
super(k);
value = v;
}
}
Entry继承了WeakReference类,其中WeakReference类是Reference类的子类,其构造方法就是调用的Reference类的构造方法:
Reference(T referent) {
this(referent, null);
}
Reference(T referent, ReferenceQueue<? super T> queue) {
this.referent = referent;
this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
}
Reference中有个get()方法:
public T get() {
return this.referent;
}
其返回的即是构造方法中传入的ThreadLocal实例
关于Reference类以及他的子类,不在本篇的讨论中,将在后续博客中进行详解
现在分析下ThreadLocal中设置值的方法,设置值的具体操作都是调用
map.set(this, value);
其内部调用的是ThreadLocalMap对象的
private void set(ThreadLocal key, Object value)方法
此方法大致说明下,不单独细细展开说明了,首先通过位操作(这时本文一开始提到的threadLocalHashCode就大显身手了)找到ThreadLocal实例在private Entry[] table中的index,然后将table[index]中的值设为新的new Entry(key, value)
取得值的方法public T get(),里面有个获取entry的代码
ThreadLocalMap.Entry e = map.getEntry(this);
具体如下:
private Entry getEntry(ThreadLocal key) {
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
首先进行位运算获取index位置,然后检查该位置的值是否存在,已经值是不是需要的key,e.get方法即是上文所说的返回对应的ThreadLocal实例,如果是的话就直接返回entry,如果没有直接在hash槽中发现对应的ThreadLocal实例,进行寻找。
下面来看看具体的使用
例子1:
public class MyThreadLocal extends ThreadLocal<Long>{
Long value = new Long(1);
@Override
public Long initialValue(){
return new Long(1);
}
public static void main(String[] args) {
MyThreadLocal longThreadLocal = new MyThreadLocal();
new Thread(new LongThread(longThreadLocal, new Long(2))).start();
new Thread(new LongThread(longThreadLocal, new Long(5))).start();
new Thread(new LongThread(longThreadLocal, new Long(8))).start();
}
}
public class LongThread implements Runnable {
private ThreadLocal<Long> local;
private Long value;
public LongThread(ThreadLocal<Long> local,Long value){
this.local = local;
this.value = value;
}
@Override
public void run() {
String threadName=Thread.currentThread().getName();
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadName+":"+local.get());
System.out.println(threadName+": value "+value);
local.set(new Long(value+local.get()));
System.out.println(threadName+": final "+local.get());
}
}
运行结果如下:
Thread-2:1
Thread-2: value 8
Thread-2: final 9
Thread-1:1
Thread-1: value 5
Thread-1: final 6
Thread-0:1
Thread-0: value 2
Thread-0: final 3
例子2:
public class ListThreadLocal extends ThreadLocal<List<String>> {
List<String> tudouList=new ArrayList<String>();
@Override
public List<String> initialValue(){
tudouList.add("a");
tudouList.add("b");
System.out.println("List size :"+tudouList.size());
return tudouList;
}
public static void main(String[] args) {
ListThreadLocal local = new ListThreadLocal();
new Thread(new ListThread(local)).start();
new Thread(new ListThread(local)).start();
new Thread(new ListThread(local)).start();
}
}
public class ListThread implements Runnable {
private ThreadLocal<List<String>> local = new ThreadLocal<List<String>>();
public ListThread(ThreadLocal<List<String>> local){
this.local = local;
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadName+":"+local.get());
local.get().add(Thread.currentThread().getName());
System.out.println(threadName + ": final " + local.get());
}
}
运行结果:
List size :2
Thread-0:[a, b]
Thread-0: final [a, b, Thread-0]
List size :5
Thread-1:[a, b, Thread-0, a, b]
Thread-1: final [a, b, Thread-0, a, b, Thread-1]
List size :8
Thread-2:[a, b, Thread-0, a, b, Thread-1, a, b]
可以看到,传递引用类型的话,还是会改变引用的值的。
Thread-2: final [a, b, Thread-0, a, b, Thread-1, a, b, Thread-2]
- 详解Java中的ThreadLocal、ThreadLocalMap和Thread之间的关系
- ThreadLocal源码解析,以及ThreadLocal、ThreadLocalMap、Thread 三者之间的关系
- ThreadLocal、ThreadLocalMap、Thread关系详细解析
- ThreadLocal,ThreadLocalMap,Thread 的相互关系以及设计原理分析
- Thread中ThreadLocal.ThreadLocalMap映射表的初始化
- 《Java源码分析》:ThreadLocal /ThreadLocalMap
- 为ThreadLocal定制的ThreadLocalMap
- Thread和Runnable之间的关系
- Thread和Runnable之间的关系
- 详解Handler和Looper、Thread的关系
- Android中的Thread、Looper、Handler之间的关系
- java中的面向对象和类之间的关系
- Handler,Thread和Runnable这三个类之间的关系
- Android中Handler 、Thread和Runnable之间的关系
- Java中的equals()和hashcode()之间关系
- Thread详解11:ThreadLocal的使用
- 【Thread】ThreadLocal模式详解
- ThreadLocal、ThreadLocalMap弱引用key
- Tomcat基础配置说明
- AndroidStudio 编译错误
- HttpClient-----4、使用HttpClient进行POST方式通信
- [1108]:最小公倍数
- hi
- 详解Java中的ThreadLocal、ThreadLocalMap和Thread之间的关系
- Chapter 5-04
- 顺序表的查找
- Html5 的Canvas使用
- iOS 网络请求类封装
- 文章标题
- spring mvc怎么获取上传文件的原路径
- mina框架分析---2
- aircrack-ng破解wifi密码基础教程