public class Thread implements Runnable {ThreadLocal.ThreadLocalMap threadLocals = null;}
使用案例
private void testThreadLocal() {Thread t = new Thread() {ThreadLocal<String> mStringThreadLocal = new ThreadLocal<>();@Overridepublic void run() {super.run();mStringThreadLocal.set("droidyue.com");mStringThreadLocal.get();}};t.start();}
源码
public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);}ThreadLocalMap getMap(Thread t) {return t.threadLocals;}void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue);}
实际上ThreadLocal的值是放入了当前线程的一个ThreadLocalMap实例中,所以只能在本线程中访问,其他线程无法访问。
在Java中,栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。而堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。
ThreadLocal的实例以及其值都是位于堆上,只是通过一些技巧将可见性修改成了线程可见。
使用InheritableThreadLocal可以实现多个线程访问ThreadLocal的值。
private void testInheritableThreadLocal() {final ThreadLocal threadLocal = new InheritableThreadLocal();//主线程中设置threadLocal.set("droidyue.com");Thread t = new Thread() {@Overridepublic void run() {super.run();//子线程中调用Log.i(LOGTAG, "testInheritableThreadLocal =" + threadLocal.get());}};t.start();}
使用InheritableThreadLocal可以将某个线程的ThreadLocal值在其子线程创建时传递过去。因为在线程创建过程中,有相关的处理逻辑。
//Thread.java//thread的成员变量ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;private void init(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc) {//code goes hereif (parent.inheritableThreadLocals != null)this.inheritableThreadLocals =ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);/* Stash the specified stack size in case the VM cares */this.stackSize = stackSize;/* Set thread ID */tid = nextThreadID();}
ThreadLocal并不会产生内存泄露,因为ThreadLocalMap在选择key的时候,并不是直接选择ThreadLocal实例,而是ThreadLocal实例的弱引用。
static class ThreadLocalMap {/*** 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;}}}
使用
- 实现单个线程单例以及单个线程上下文信息存储,比如交易id等。
- 实现线程安全,非线程安全的对象使用ThreadLocal之后就会变得线程安全,因为每个线程都会有一个对应的实例。
- 承载一些线程相关的数据,避免在方法中来回传递参数。
