ThreadLocal浅析
来源:互联网 发布:win10优化 gui 编辑:程序博客网 时间:2024/04/29 13:14
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使用浅析
- MP3文件格式解析
- SQL 2005 with(nolock)详解
- java /n /r /t
- Tomcat webapps与work的区别
- 修改linux下MySQL编码
- ThreadLocal浅析
- Runtime类
- SA Note
- HDU 2001 2002
- 关于Android的组件名
- POJ 3844 Divisible Subsequences
- Cocoa Programming for Mac OS X 第三章(Objective-C)摘录
- 设置Linux下Mysql表名不区分大小写
- 如何从DirectFB中获取cairo所需要的surface