ThreadLocal浅析
来源:互联网 发布:java求二进制方法 编辑:程序博客网 时间:2024/05/16 10:41
1.目的
ThreadLocal目的是保存一些线程级别的全局变量,比如connection,或者事务上下文,避免这些值需要一直通过函数参数的方式一路传递。
2. 常见用法
- public class Test2 {
- public static void main(String[] args) throws InterruptedException {
- testThreadLocal();
- }
- private static void testThreadLocal() {
- Util.setGlobalName("zili.dengzl");
- new Foo().printName();
- }
- }
- class Foo{
- public void printName(){
- System.out.println("globalName="+Util.getGlobalName());
- }
- }
- class Util {
- private static final ThreadLocal<String> globalName = new ThreadLocal<String>();
- public static String getGlobalName() {
- return globalName.get();
- }
- public static void setGlobalName(String name) {
- globalName.set(name);
- }
- }
3.实现分析
要实现上面这样的功能,最简单的想法是用一个Map<Thread,T>,如下:
- class MockThreadLocal<T> {
- private Map<Thread, T> map = new HashMap<Thread, T>();
- public T get() {
- return (T) map.get(Thread.currentThread());
- }
- public void set(T value) {
- map.put(Thread.currentThread(), value);
- }
- }
这样也能实现ThreadLocal的效果,但是有一个问题,当对应的线程消失后,map中对应的线程值并不会被回收,从而造成内存泄露。
事实上ThreadLocal是这样做的:
- /**
- * 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.
- *
- * @return the current thread's value of this thread-local
- */
- public T get() {
- Thread t = Thread.currentThread();
- ThreadLocalMap map = getMap(t);
- if (map != null) {
- ThreadLocalMap.Entry e = map.getEntry(this);
- if (e != null)
- return (T)e.value;
- }
- return setInitialValue();
- }
注意这里如果取到没有该线程对应的值,会调用setInitialValue();,最终调用initialValue()生成一个值,这也是我们很多场景下要override这个方法的原因;
下面看一下getMap(Thread t)方法:
- ThreadLocalMap getMap(Thread t) {
- return t.threadLocals;
- }
在Thread类中:
- /* ThreadLocal values pertaining to this thread. This map is maintained
- * by the ThreadLocal class. */
- ThreadLocal.ThreadLocalMap threadLocals = null;
由此可见,所有的ThreadLocal的信息,最终是关联到Thread上的,线程消失后,对应的Thread对象也被回收,这时对应的ThreadLocal对象也会被回收。
这里为什么是一个ThreadLocalMap呢,因为一个线程可以有多个ThreadLocal变量,通过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);
- }
最后要注意的一点是,ThreadLocalMap的Entry是一个weakReference:
- /**
- * The entries in this hash map extend WeakReference, using
- * its main ref field as the key (which is always a
- * ThreadLocal object). Note that null keys (i.e. entry.get()
- * == null) mean that the key is no longer referenced, so the
- * entry can be expunged from table. Such entries are referred to
- * as "stale entries" in the code that follows.
- */
- static class Entry extends WeakReference<ThreadLocal> {
- /** The value associated with this ThreadLocal. */
- Object value;
- Entry(ThreadLocal k, Object v) {
- super(k);
- value = v;
- }
- }
这里主要因为ThreadLocalMap的key是ThreadLocal对象,如果某个ThreadLocal对象所有的强引用没有了,不能因为ThreadLocalMap的引用导致他不能被回收。
附:
这里补充一下weakReference的用法供参考(当强引用不存在时,下次垃圾回收会回收弱引用所引用的对象):
- Object o = new Object();
- WeakReference<Object> ref = new WeakReference<Object>(o);
- System.out.println(ref.get());
- o=null;
- System.gc();
- System.out.println(ref.get());
结果输出:
- java.lang.Object@de6ced
- null
- ThreadLocal浅析
- ThreadLocal浅析
- 浅析ThreadLocal
- ThreadLocal浅析
- ThreadLocal浅析
- ThreadLocal浅析
- ThreadLocal浅析
- 浅析ThreadLocal
- 浅析ThreadLocal
- 浅析ThreadLocal
- ThreadLocal浅析
- 浅析 ThreadLocal
- 浅析 ThreadLocal
- ThreadLocal浅析
- ThreadLocal浅析
- ThreadLocal浅析
- Java ThreadLocal使用浅析
- Java ThreadLocal使用浅析
- java小知识点
- Kernel Source片段 -- 协议处理函数的组织
- Windows Mobile 6 中为开发人员提供的新功能
- Discount 折扣
- 1510. Mispelling 喵~o( =∩ω∩= )m
- ThreadLocal浅析
- [Unity3d]水果忍者-切水果功能
- jetty学习1-SelectChannelConnector
- Smartphone 应用程序安全与代码签名模型开发人员实用指南
- 以MAD为例学习ENVI编程
- Android 自定义SeekBar控件
- Jetty6控制/通讯主要源代码分析
- Hibernate 中的主键生成
- 高手速成android开源项目【View篇】