java threadlocal包_Java并发包(ThreadLocal )第一节

一、ThreadLocal能做什么?

"线程本地变量"或"线程局部变量"

作用域为当前线程,而不是某个具体任务。

声明周期和线程的声明周期相同(JDK实现中比线程的生命周期更短,减少了内存泄漏的可能)。

线程与任务剥离,从而达到线程封闭的目的。

二、存在的问题

线程死亡之后,任务对象可能仍然存在(这才是最普遍的情况),从而ThreadLocal对象仍然存在。我们不能要求线程在死亡之前主动删除其使用的ThreadLocal对象,所以valueMap中该线程对应的entry()无法回收。

这种实现“将线程相关的域封闭于任务对象,而不是线程中”。所以ThreadLocal的实现中最重要的一点就是——“将线程相关的域封闭在当前线程实例中”,虽然域仍然在任务对象中声明、set和get,却与任务对象无关。

三、ThreadLocal源码分析

void set(T value)方法

源码:

/**

* Sets the current thread's copy of this thread-local variable

* to the specified value. Most subclasses will have no need to

* overridethis method, relying solely on the {@link#initialValue}

* method to set the values of thread-locals.

*

* @paramvalue the value to be stored in the current thread's copy of

* this thread-local.

*/

public void set(T value) {

//1. 获取当前线程实例对象

Thread t = Thread.currentThread();

//2. 通过当前线程实例获取到ThreadLocalMap对象

ThreadLocalMap map = getMap(t);

if (map != null)

//3. 如果Map不为null,则以当前threadLocl实例为key,值为value进行存入

map.set(this, value);

else

//4.map为null,则新建ThreadLocalMap并存入value

createMap(t, value);

}

数据value是真正的存放在了ThreadLocalMap这个容器中了,并且是以当前threadLocal实例为key

获取ThreadLocalMap

//******

//ThreadLocal values pertaining to this thread. This map is maintained

/* by the ThreadLocal class. */

ThreadLocal.ThreadLocalMap threadLocals = null;

/*******

/**

* Get the map associated with a ThreadLocal. Overridden in

* InheritableThreadLocal.

*

* @param t the current thread

* @returnthe map

*/

ThreadLocalMap getMap(Thread t) {

return t.threadLocals;

}

设置value时,要根据当前线程t获取一个ThreadLocalMap类型的map,真正的value保存在这个map中。这验证了之前的一部分想法——ThreadLocal变量保存在一个​“线程相关”的map​中。

也就是说ThreadLocalMap的引用是作为Thread的一个成员变量,被Thread进行维护的。回过头再来看看set方法,当map为Null的时候会通过​createMap(t,value)​方法:

/**

* Create the map associated with a ThreadLocal. Overridden in

* InheritableThreadLocal.

*

* @paramt the current thread

* @paramfirstValue value for the initial entry of the map

*/

void createMap(Thread t, T firstValue) {

t.threadLocals = new ThreadLocalMap(this, firstValue);

}

该方法就是new一个ThreadLocalMap实例对象,然后同样以当前threadLocal实例作为key,值为value存放到threadLocalMap中,然后将当前线程对象的threadLocals赋值为threadLocalMap。

set方法总结:

通过当前线程对象thread获取该thread所维护的threadLocalMap,

若threadLocalMap不为null,则以threadLocal实例为key,值为value的键值对存入threadLocalMap,

若threadLocalMap为null的话,就新建threadLocalMap然后在以threadLocal为键,值为value的键值对存入即可。

T get()方法

/**

* Returns the value in the current thread's copy of this

* thread-local variable. If the variable has no value for the

* current thread, it is first initialized to the value returned

* by an invocation of the {@link#initialValue} method.

*

* @returnthe current thread's value of this thread-local

*/

public T get() {

//1. 获取当前线程的实例对象

Thread t = Thread.currentThread();

//2. 获取当前线程的threadLocalMap

ThreadLocalMap map = getMap(t);

if (map != null) {

//3. 获取map中当前threadLocal实例为key的值的entry

ThreadLocalMap.Entry e = map.getEntry(this);

if (e != null) {

@SuppressWarnings("unchecked")

//4. 当前entitiy不为null的话,就返回相应的值value

T result = (T)e.value;

return result;

}

}

//5. 若map为null或者entry为null的话通过该方法初始化,并返回该方法返回的value

return setInitialValue();

}

/**

* Variant of set() to establish initialValue. Used instead

* of set() in case user has overridden the set() method.

*

* @returnthe initial value

*/

private T setInitialValue() {

T value = initialValue();

Thread t = Thread.currentThread();

ThreadLocalMap map = getMap(t);

if (map != null)

map.set(this, value);

else

createMap(t, value);

return value;

}

protected T initialValue() {

return null;

}

这个方法是protected修饰的也就是说继承ThreadLocal的子类可重写该方法,实现赋值为其他的初始值。

关于get方法来总结一下:

通过当前线程thread实例获取到它所维护的threadLocalMap,然后以当前threadLocal实例为key获取该map中的键值对(Entry),若Entry不为null则返回Entry的value。如果获取threadLocalMap为null或者Entry为null的话,就以当前threadLocal为Key,value为null存入map后,并返回null。

remove()

/**

* Removes the current thread's value for this thread-local

* variable. If this thread-local variable is subsequently

* {@linkplain#get read} by the current thread, its value will be

* reinitialized by invoking its {@link#initialValue} method,

* unless its value is {@linkplain#set set} by the current thread

* in the interim. This may result in multiple invocations of the

* {@codeinitialValue} method in the current thread.

*

* @since1.5

*/

public void remove() {

//1. 获取当前线程的threadLocalMap

ThreadLocalMap m = getMap(Thread.currentThread());

if (m != null)

//2. 从map中删除以当前threadLocal实例为key的键值对

m.remove(this);

}

删除数据当然是从map中删除数据,先获取与当前线程相关联的threadLocalMap然后从map中删除该threadLocal实例为key的键值对即可。

参考链接:

《java高并发程序设计》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值