ThreadLocal

相關連接:多線程

  http://www.jianshu.com/p/a8fa72e708d3less

 

  建立Handler的時候,須要先建立當前線程的Looper,Android默認在啓動的時候爲咱們建立的  主線程的Looper,因此咱們能夠在主線程直接建立Handler。async

  可是在子線程建立Handler的時候,咱們必須先手動建立Looper,才能建立Handler,不然會拋出一個必須調用Looper.prepare()的異常信息。ide

  緣由:      oop

public Handler(Callback callback, boolean async) {
  //省略

  mLooper = Looper.myLooper();
  if (mLooper == null) {
      throw new RuntimeException(
          "Can't create handler inside thread that has not called Looper.prepare()");
  }
  //省略
}

  問題:ui

    相同的代碼,爲何在主線程建立就能夠,在子線程建立就異常???爲何在子線程中,經過Looper.myLooper()方法獲取的就是爲空呢?this

  查看Looper.myLooper()源碼,可知道緣由:ThreadLocal獲取的是「當前線程」的Looperspa

sThreadLocal.get();

  ThreadLocal在何時set值的那?--- 在Looper中源碼中線程

private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));
}

  ThreadLocal的初始化:--- 在Looper中源碼中code

    // sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

    看註釋能夠知道,sThreadLocal.get()以前,必須Looper.prepare(),不然get到的值爲null。

 

ThreadLocal是什麼? 

    看一下官方的解釋:

Implements a thread-local storage, that is, a variable for which each thread
has its own value. All threads share the same {@code ThreadLocal} object,
but each sees a different value when accessing it, and changes made by one
thread do not affect the other threads. The implementation supports
{@code null} values.

    意思是說:ThreadLocal實現與線程相關的存儲。全部線程共享一個ThreadLocal對象,可是不一樣的線程有本身的值。而且當一個線程的值發生改變以後,不會影響其餘的線程的值。

      因此這就解釋了爲何 在子線程中,若是不Looper.prepare()就直接建立Handler的時候,會拋出異常。

 

ThreadLocal並非線程,它的做用是能夠在每一個線程中存儲數據,,數據存儲之後,只有在指定線程中能夠獲取到存儲的數據。對於其它線程來講沒法獲取到數據。
ThreadLocal是一個關於建立線程局部變量的類。一般狀況下,咱們建立的變量是能夠被任何一個線程訪問並修改的。而使用ThreadLocal建立的變量只能被當前線程訪問,其餘線程則沒法訪問和修改。

 

下面看一下ThreadLocal部分源碼:

    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 getMap(Thread t) {
        return t.threadLocals;
    }

    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);//this表明的是ThreadLocal
    }

    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();//null
    }


    private T setInitialValue() {
        T value = initialValue();//null
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

    protected T initialValue() {
        return null;
    }

   全部線程共用一個ThreadLocal,每個線程都有一個ThreadLocalMap,key爲當前線程的ThreadLocal。

 

  因此從此,若是多線程的每個線程都有一個相同變量,可是每一個線程的變量值只有當前線程本身能夠修改,不受其它線程的影響,那麼你就能夠用ThreadLocal。多線程共享同一個ThreadLocal對象。    

相關文章
相關標籤/搜索