[3]如何使用ThreadLocal在多线程间共享

1,077 阅读2分钟

ThreadLocal是什么东东呢

ThreadLocal = “Thread” 的“Local”信息 ,是一个线程独有信息保存的类。

1、通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。 2、而使用ThreadLocal创建的变量只能被当前线程访问,其他线程无法访问和修改。

怎么做到的呢

往ThreadLocal 里面塞数据

threadlocal.set(value)

->>


public void set(T value) {
    Thread t = Thread.currentThread(); 
    ThreadLocalMap map = getMap(t); 
    if (map != null) 
        map.set(this, value);
    else 
    createMap(t, value); 
}

我们看到是从这里获取的map:ThreadLocalMap

ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

这里创建的ThreadLocalMap

void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

ThreadLocalMap作为Thead的成员变量

class Thread implements Runnable { 
    /* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ 
    ThreadLocal.ThreadLocalMap threadLocals = null;
}

所以最终看到了这里,就明白了,原来同一个线程中通过ThreadLocal设置的信息都保存到了当前线程的Map中,引用关系是这样的ThreadLocal-》ThreadLocalMap-》Thread 那么ThreadLocalMap作为一个线程的变量,根据每个线程的变量是隔离的,所以这样就回到了文章最前面的ThreadLocal只能访问和修改当前线程的信息

但是,Map会不会内存泄露呢,不及时清理怎么办?

看代码吧~

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; 
        }
    }
}

这里是一个弱引用,所以没事情啦!该释放就自然释放了!

但是我们有办法在父子线程之间传递信息么

答案是可以的

final ThreadLocal threadLocal = new InheritableThreadLocal(); threadLocal.set("google.com"); 
    Thread t = new Thread() { 
        @Override public void run() {
            super.run(); 
            Log.i("test", "InheritableThreadLocal =" + threadLocal.get());
        }
    };
t.start();
//Thread.java 
private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc) {
    //code goes here 
    if (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(); 
}

但是Android开发中,遇到的很少了就。