天天看點

Android與Java中的ThreadLocal

每次的學習都應該記錄下來~!~!

這幾天看Android的Handle、Loop、Message。以前自己總是在用但沒有仔細的去看過源碼,檢視源代碼的時候發現ThreadLocal這個類的使用。這時發現好熟悉EvenBus裡面好像也用到了這個類,于是在網上翻看了好多關于ThreadLocal的文章。

ThreadLocal的作用是提供線程内的局部變量,這種變量線上程的生命周期内起作用,減少同一個線程内多個函數或者元件之間一些公共變量的傳遞的複雜度。

//ThreadLocal提供get和set方法可以擷取目前線程中的ThreadLocal<Object>的值
    public T get();
    public void set(T value);      

ThreadLocal不是解決多線程安全并發通路資源的在學習的過程中自己發現了以前很少使用的一個叫做​​AtomicInteger​​,他好像可以提供所線程并發通路統一資源的問題,因為它能保證資源的原子性。

Android與Java中的ThreadLocal

上圖很形象的解釋的ThreadLocal的運用,Thread中有一個ThreadLocal.ThreadLocalMap成員變量,用它來存儲目前Thread中的​

​ThreadLocal<Object>​

​對象,以ThreadLocal為K,以Object為V進行一對一的存儲。

一個使用ThreadLocal的Demo:

public class ThreadLocalTest {
    static ThreadLocal<String> threadLocal = new ThreadLocal<String>() {
        //設定threadLocal線上程中的初始值
        @Override
        protected String initialValue() {
            return "Init";
        }
    };
    static class MyThread implements Runnable {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + threadLocal.get());
            threadLocal.set(Thread.currentThread().getName());
            System.out.println(Thread.currentThread().getName() + threadLocal.get());
        }
    }

    public static void main(String[] args) {
        new Thread(new MyThread()).start();
        new Thread(new MyThread()).start();
        new Thread(new      

輸出結果:

Thread-1Init
Thread-2Init
Thread-0Init
Thread-2Thread-2
Thread-1Thread-1
Thread-0Thread-0      

JDK中:

Android與Java中的ThreadLocal

SDK中:

Android與Java中的ThreadLocal

JDK和SDK的ThreadLocal其實在構想上是一樣的,隻不過具體代碼實作是有些不同。

JDK使用的是ThreadLocal.ThreadLocalMap,它的靜态内部類是Entry,ThreadLocalMap内部有一個數組Entry[] table,ThreadLocal對象執行個體有一個threadLocalhashCode變量

private static final int HASH_INCREMENT = 0x61c88647;
private final int threadLocalHashCode = nextHashCode();
private static int nextHashCode() {
    return nextHashCode.getAndAdd(HASH_INCREMENT);
}
private static AtomicInteger nextHashCode = new      

和一個nexhasCode靜态變量。一個JVM中每産生一個ThreadLocal對象該對象的threadLocalHashCode的值增加​​0x61c88647​​​。為什麼會增加​​0x61c88647​​因為:

//ThreadLocalMap:
private void set(ThreadLocal key, Object value) {
    Entry[] tab = table;
    int len = tab.length;
    //這樣生成的index才不會重複
    int i = key.threadLocalHashCode & (len-1);
    ……
}      

然後再擷取​

​ThreadLocal<Object>​

​值得時候根據目前的執行個體的trheadLocalHashCode作為ThreadLocalMap的index找到對應的Object。

SDK:中用ThreadLocal.Values代替了,JDK中的ThreadLocal.ThreadLocalMap和ThreadLocal.ThreadLocalMap.Entry。

private final int hash = hashCounter.getAndAdd(0x61c88647 * 2);
private static AtomicInteger hashCounter = new AtomicInteger(0);
private final Reference<ThreadLocal<T>> reference
            = new WeakReference<ThreadLocal<T>>(this);      
//ThreadLocal:
public T get() {
    // Optimized for the fast path.
    Thread currentThread = Thread.currentThread();
    Values values = values(currentThread);
    if (values != null) {
        Object[] table = values.table;
        int index = hash & values.mask;
        if (this.reference == table[index]) {
            return (T) table[index + 1];
        }
    } else {
        values = initializeValues(currentThread);
    }

    return (T) values.getAfterMiss(this);
}
//ThreadLodal.Vaules:
private void initializeTable(int capacity) {
    this.table = new Object[capacity * 2];
    this.mask = table.length - 1;
    this.clean = 0;
    this.maximumLoad = capacity * 2 / 3; // 2/3
}
Object getAfterMiss(ThreadLocal<?> key) {
    Object[] table = this.table;
    //産生table.length之類的不重複的非奇數
    int index = key.hash & mask;
    ……
    table[index] = key.reference;
    table[index + 1] = value;
    ……               
}