Java ThreadLocal使用
它是java中的一个为每个线程单独保存数据的类,也就是线程间数据隔离。
1.使用
public static void main(String[] args) throws Exception {
//定义一个ThreadLocal
ThreadLocal<String> local = new ThreadLocal<String>();
new Thread(new Runnable() {
@Override
public void run() {
//为当前线程设置一个值
local.set("thread1");
try {
//线程休眠为了等一下其它线程设置值
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//打印
System.out.println("第1个线程值"+local.get());
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
local.set("thread2");
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("第2个线程值"+local.get());
}
}).start();
}
结果:
说明每个线程取到了自己的数据。
2.原理
先看一看ThreadLocal的set方法:
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
//获取当前线程
Thread t = Thread.currentThread();
//获取ThreadLocalMap对象
ThreadLocalMap map = getMap(t);
if (map != null)
//设置值
map.set(this, value);
else
//创建ThreadLocalMap对象
createMap(t, value);
}
先看一下getMap(t);我们发现getMap(t);取得是当前线程的threadLocals属性也就是说变量实际是存在每个线程自己的属性中的。
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
然后我们看一下ThreadLocalMap是什么类。
他是一个ThreadLocal中的内部类类似Map,他里面也有一个重要的内部类` static class Entry extends WeakReference<ThreadLocal<?>>
注意它是一个弱引用。
关于java中引用类型以后有时间再写。
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
//将键设置为弱引用
super(k);
value = v;
}
}
接下来看一下创建ThreadLocalMap对象 createMap(t, value);
void createMap(Thread t, T firstValue) {
//这个this是当前ThreadLocal对象
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
//重点是这里将当前ThreadLocal对象设置为弱引用了
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
其实就是创建一个ThreadLocalMap将key,value存进去。
最后get方法就相对简单了
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
就是从当前线程取出ThreadLocalMap再根据当前ThreadLocal对象取出值。
3.内存泄漏问题
ThreadLocalMap的key是当前ThreadLocal为一个弱引用,当我们不想使用ThreadLocal时将它设置为null了,也就是要被垃圾回收器回收了,但是此时我们的ThreadLocalMap生命周期和Thread的一样,它不会回收,这时候就出现了一个现象。那就是ThreadLocalMap的key没了,但是value还在,这就造成了内存泄漏。
所以最好在不使用ThreadLocal时,调用一下remove()方法移除存储的值。
这是我总结的我对ThreadLocal的理解,有不对的地方大家可以讨论。
本文地址:https://blog.csdn.net/wste3567/article/details/113970590
上一篇: 放嘴里的是‘食指’
下一篇: Java开发常用类库之Hutool