简介
ThreadLocal类允许我们创建只能被同一个线程读写的变量。因此,如果一段代码含有一个ThreadLocal变量的引用,即使两个线程同时执行这段代码,它们也无法访问到对方的ThreadLocal变量。
初始化
//简单初始化
public static final ThreadLocal<T> holder = new ThreadLocal<T>();
holder.set("test"); // 存
holder.get(); // 取
//带初始值初始化
private ThreadLocal<String> myThreadLocal = new ThreadLocal<String>() {
@Override
protected String initialValue() {
return "This is the initial value";
}
};
例子1
public class ThreadLocalExample {
public static class MyRunnable implements Runnable {
private ThreadLocal threadLocal = new ThreadLocal();
@Override
public void run() {
threadLocal.set((int) (Math.random() * 100D));
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
System.out.println(threadLocal.get());
}
}
public static void main(String[] args) {
MyRunnable sharedRunnableInstance = new MyRunnable();
Thread thread1 = new Thread(sharedRunnableInstance);
Thread thread2 = new Thread(sharedRunnableInstance);
thread1.start();
thread2.start();
}
}
源码分析
1、Thread类中持有ThreadLocal.ThreadLocalMap threadLocals
ThreadLocal.ThreadLocalMap threadLocals = null;
2、ThreadLocal的存取是对Thread类中的ThreadLocalMap进行操作;
ThreadLocalMap中的set方法中的key为ThreadLocal对象
public void set(T value) {
//获取当前线程
Thread t = Thread.currentThread();
//当前线程的ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null)
//key为this,表示当前ThreadLocal对象
map.set(this, value);
else
createMap(t, value);
}
3、ThreadLocalMap中的set方法,如果发生了Hash碰撞,在循环条件中可以看到nextIndex,即找到下个位置存放。该Hash碰撞冲突解决方式属于线性探测再散列。
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal k = e.get();
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
4、ThreadLocalMap中的Entry数组为弱引用
static class Entry extends WeakReference<ThreadLocal> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal k, Object v) {
super(k);
value = v;
}
}
5、内存溢出问题
http://blog.xiaohansong.com/2016/08/06/ThreadLocal-memory-leak/