Java基础知识整理6:ThreadLocal
JDK描述
public class ThreadLocal
extends Object
该类提供了线程局部 (thread-local)变量。这些变量不同于普通变量,每个线程都有自己的局部拷贝,独立于变量的初始副本。ThreadLocal的实例通常是类中的 private static字段,这些字段与某一个线程的状态关联起来(例如,用户 ID 或交易 ID)
例如,下面的类生成每个线程唯一的局部标识符。 线程 ID 是在第一次调用 UniqueThreadIdGenerator.getCurrentThreadId() 时分配的,在后续调用中不会更改。
import java.util.concurrent.atomic.AtomicInteger;
public class UniqueThreadIdGenerator {
private static final AtomicInteger uniqueId = new AtomicInteger(0);
private static final ThreadLocal < Integer > uniqueNum =
new ThreadLocal < Integer > () {
@Override protected Integer initialValue() {
return uniqueId.getAndIncrement();
}
};
public static int getCurrentThreadId() {
return uniqueId.get();
}
} // UniqueThreadIdGenerator
每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。
使用
- 在类中定义一个static的ThreadLocal,ThreadLocal内部有一个map保存每个线程的值;多个线程执行时,根据Thread.getCurrentThread()获取其对应的值。
private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {
public Integer initialValue() {
return 0;
};
};
public class TestThreadLocal {
//多个线程共享使用,内部有map,保存每个线程的值
private static final ThreadLocal<Integer> value = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 0;
}
};
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new Thread(new MyThread(i)).start();
}
}
MyThread的run方法中
public void run() {
System.out.println("线程" + index + "的初始value:" + value.get());
for (int i = 0; i < 10; i++) {
value.set(value.get() + i);
}
System.out.println("线程" + index + "的累加value:" + value.get());
}
}
代码分析
ThreadLocal类实现了三个接口
- Serializable 支持序列化
ThreadLocal的变量
- private final char value[] 保存字符
字符数组和offset及count都是final的,必须在构造方法中初始化,之后不能修改。
构造方法
- public ThreadLocal() 空实现
其他方法
- public T get() 获取值
- public void remove()
- public void set(T value)
//获取map中的值,首次调用时为null,会执行setInitialValue方法,
public T get() {
Thread t = Thread.currentThread();//获取当前线程实例
ThreadLocalMap map = getMap(t);//获取该线程实例对应的Map
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
//首次调用时
return setInitialValue();
}
//首次调用get会调用该方法,其逻辑为创建map,调用initialValue()并设置到map中
private T setInitialValue() {
T value = initialValue();//调用initialValue方法获取初始值,该方法会被重写
Thread t = Thread.currentThread();//获取当前线程
ThreadLocalMap map = getMap(t);//获取线程对应的Map
if (map != null)
map.set(this, value);//不为空,设置值
else
createMap(t, value);//为空,创建map并设置值
return value;
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;//ThreadLocal.ThreadLocalMap threadLocals
}
ThreadLocalMap是ThreadLocal的内部类,ThreadLocalMap内部有一个Entry类,保存值
//设置线程的value,若无map,则创建后再设置
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
总结
- ThreadLocal [http://blog.csdn.net/lufeng20/article/details/24314381]
- 深入剖析ThreadLocal https://zhuanlan.zhihu.com/p/20213204
浙公网安备 33010602011771号