免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
賭十包辣條,你一定沒見過這么通透的ThreadLocal講解

1、看個熱鬧

? ? ? ?鑒于普羅大眾都喜歡看熱鬧,咱們先來看個熱鬧再開工吧!

?

場景一:?

中午了, 張三、李四和王五一起去食堂大菜吃飯。食堂剛經(jīng)營不久,還很簡陋,負(fù)責(zé)打菜的只有一位老阿姨。

?張三:我要一份雞腿。

?李四:我要一份小雞燉蘑菇。

?張三:我再要一份紅燒肉。

?王五:我要一份紅燒排骨。

?李四:我不要小雞燉蘑菇了,換成紅燒鯽魚。

?王五:我再要一份椒鹽蝦。

?張三:我再要一份梅菜扣肉。

?......

?張三:我點的紅燒肉,為啥給我打紅燒鯽魚?

?李四:我的紅燒鯽魚呢?

?王五:我有點紅燒肉嗎?

?......

?李四:我點了15元的菜,為啥扣我20?

?王五:我點了20元的菜,只扣了我15元,賺了,竊喜!

?張三:我已經(jīng)刷了卡了,怎么還叫我刷卡?

?......

?老阿姨畢竟上了年紀(jì),不那么利索,這幾個小伙子咋咋呼呼,快言快語,老阿姨也被攪暈了,手忙腳亂,忙中出錯,這仨小伙也是怨聲載道。

?場景二:

?食堂領(lǐng)導(dǎo)看到這個場景,趕緊要求大家排隊,一個一個來。后來,老阿姨輕松多了,也沒有再犯錯了。

?但是,新的問題又來了,打菜的人當(dāng)中,很多妹子很磨嘰,點個菜猶猶豫豫想半天。

?張三:太慢了,我快餓死了!

?李四:再這么慢,下次去別家!

?王五:我等得花兒都謝啦!

?趙六:啥?我點了啥菜,花了多少錢,其它人怎么都知道?是阿姨多嘴了,還是其它人偷偷關(guān)注我很久了?太不安全了,一點隱私都沒有,以后不來了。

?......

?場景三:

? 領(lǐng)導(dǎo)聽到這些怨言,心里很不是滋味,大手一揮:擴(kuò)大經(jīng)營,以后為你們每一個人開一個流動窗口并請一位私人阿姨,只為你一個人服務(wù)!

? 從此,再也沒有怨言,阿姨也沒有再犯錯了,皆大歡喜......

?

? ? ? ?場景一就像多個線程同時去操作一個數(shù)據(jù),最終的結(jié)果就是混亂。于是出現(xiàn)了同步鎖synchronized,同一時刻只運行一個線程操作,就像場景二,大家先來后到排隊,混亂的問題解決了。但是此時一個線程在操作的時候,其它線程只能閑等著,而且這些數(shù)據(jù)是共享的,每個線程希望擁有只能自己操作的私人數(shù)據(jù),ThreadLocal就正好滿足了這個需求。

? ? ? ?所以,相比于synchronized,Threadlocal通過犧牲空間來換取時間和效率。

?

2、ThreadLocal簡介?

? ? ? ?ThreadLocal官方的介紹為:

1 /**2  * This class provides thread-local variables.  These variables differ from3  * their normal counterparts in that each thread that accesses one (via its4  * {@code get} or {@code set} method) has its own, independently initialized5  * copy of the variable.  {@code ThreadLocal} instances are typically private6  * static fields in classes that wish to associate state with a thread (e.g.,7  * a user ID or Transaction ID).8  */

? ? ? ?大致意思是:ThreadLocal提供了線程本地變量。這些變量與一般變量相比,其不同之處在于,通過它的get()和set()方法,每個線程可以訪問自己獨立擁有的初始變量副本。翻譯成人話就是,ThreadLocal為每一個線程開辟了一個獨立的存儲器,只有對應(yīng)的線程才能夠訪問其數(shù)據(jù),其它線程則無法訪問。對應(yīng)于前文的場景,就像食堂為每一個人安排了一個窗口和專屬阿姨為其打菜,這個過程中,這個窗口和阿姨就是其專屬的獨立的資源,其他人就無從知道他點了什么菜,花了多少錢。

?

3、ThreadLocal的簡單使用示例?

? ? 是騾子是馬,先拉出來溜溜!先直觀看看它的能耐,再來了解它豐富的內(nèi)心:

 1 // =========實例3.1======== 2 private ThreadLocal<String> mThreadLocal = new ThreadLocal<>(); 3 private void testThreadLocal() throws InterruptedException { 4     mThreadLocal.set("main-thread"); 5     Log.i("threadlocaldemo", "result-1="   mThreadLocal.get()); 6     Thread thread_1 = new Thread() { 7         @Override 8         public void run() { 9             super.run();10             mThreadLocal.set("thread_1");11             Log.i("threadlocaldemo", "result-2="   mThreadLocal.get());12         }13     };14     thread_1.start();15     //該句表示thread_1執(zhí)行完后才會繼續(xù)執(zhí)行16     thread_1.join();17     Thread thread_2 = new Thread() {18         @Override19         public void run() {20             super.run();21             Log.i("threadlocaldemo", "result-3="   mThreadLocal.get());22         }23     };24     thread_2.start();25     //該句表示thread_2執(zhí)行完后才會繼續(xù)執(zhí)行26     thread_2.join();27     Log.i("threadlocaldemo", "result-4="   mThreadLocal.get());28 }

?在主線程中調(diào)用這個方法,運行結(jié)果:

1 12-13 13:42:50.117 25626-25626/com.example.demos I/threadlocaldemo: result-1=main-thread2 12-13 13:42:50.119 25626-25689/com.example.demos I/threadlocaldemo: result-2=thread_13 12-13 13:42:50.119 25626-25690/com.example.demos I/threadlocaldemo: result-3=null4 12-13 13:42:50.120 25626-25626/com.example.demos I/threadlocaldemo: result-4=main-thread

? ? ? ?看到這個結(jié)果會不會驚掉下巴呢?明明在第9行中set了值,第10行中也得到了對應(yīng)的值,但第20行的get得到的卻是null,第26行得到的是第3行set的值。這就是ThreadLocal的神奇功效,主線程set的值,只能在主線程get到;thread_1內(nèi)部set的值,thread_1中才能get;thread_2中沒有set,所以get到的就是null。

? ? ? ?而實現(xiàn)這,不要999,也不要99,只要3......三步即可:

1 ThreadLocal<T> mThreadLocal = new ThreadLocal<>();2 mThreadLocal.set(T);3 mThreadLocal.get();

就是這么方便,就是這么簡潔!

?

4、提供的4個主要接口

? ? ? ?ThreadLocal以其使用簡單,風(fēng)格簡潔讓人一見傾心。它對外提供的接口很少,當(dāng)前SDK中,主要有4個:

1 public void set(T value) { }  2 public T get() { }  3 public void remove() { }  4 protected T initialValue() { }  

為了保持對這些方法說明的原滋原味,我們直接通過源碼中對其的注釋說明來認(rèn)識它們。

?(1)set()

 1 /** 2  * Sets the current thread's copy of this thread-local variable 3  * to the specified value.  Most subclasses will have no need to 4  * override this method, relying solely on the {@link #initialValue} 5  * method to set the values of thread-locals. 6  * 7  * @param value the value to be stored in the current thread's copy of 8  *        this thread-local. 9  */10 public void set(T value)

設(shè)置當(dāng)前線程的ThreadLocal值為指定的value。大部分子類沒有必要重寫該方法,可以依賴initialValue()方法來設(shè)置ThreadLocal的值。

? (2)get()

1 /**2  * Returns the value in the current thread's copy of this3  * thread-local variable.  If the variable has no value for the4  * current thread, it is first initialized to the value returned5  * by an invocation of the {@link #initialValue} method.6  *7  * @return the current thread's value of this thread-local8  */9 public T get()

用于獲取當(dāng)前線程所對應(yīng)的ThreadLocal值。如果當(dāng)前線程下,該變量沒有值,會通過調(diào)用initialValue()方法返回的值對其進(jìn)行初始化。

? (3)remove()

 1 /** 2  * Removes the current thread's value for this thread-local 3  * variable.  If this thread-local variable is subsequently 4  * {@linkplain #get read} by the current thread, its value will be 5  * reinitialized by invoking its {@link #initialValue} method, 6  * unless its value is {@linkplain #set set} by the current thread 7  * in the interim.  This may result in multiple invocations of the 8  * {@code initialValue} method in the current thread. 9  *10  * @since 1.511  */12  public void remove()

? ? ? ?該接口是從JDK1.5開始提供的,用于刪除當(dāng)前線程對應(yīng)的ThreadLocal值,從而減少內(nèi)存占用。在同一線程中,如果該方法被調(diào)用了,隨后再調(diào)用get()方法時,會使得initialValue()被調(diào)用,從而ThreadLocal的值被重新初始化,除非此時在調(diào)用get()前調(diào)用了set()來賦值。該方法可能導(dǎo)致initialValue()被多次調(diào)用。該方法可以不用顯示調(diào)用,因為當(dāng)線程結(jié)束后,系統(tǒng)會自動回收線程局部變量值。所以該方法不是必須調(diào)用的,只不過顯示調(diào)用可以加快內(nèi)存回收。

? (4)initialValue()

 1 /** 2  * Returns the current thread's "initial value" for this 3  * thread-local variable.  This method will be invoked the first 4  * time a thread accesses the variable with the {@link #get} 5  * method, unless the thread previously invoked the {@link #set} 6  * method, in which case the {@code initialValue} method will not 7  * be invoked for the thread.  Normally, this method is invoked at 8  * most once per thread, but it may be invoked again in case of 9  * subsequent invocations of {@link #remove} followed by {@link #get}.10  *11  * <p>This implementation simply returns {@code null}; if the12  * programmer desires thread-local variables to have an initial13  * value other than {@code null}, {@code ThreadLocal} must be14  * subclassed, and this method overridden.  Typically, an15  * anonymous inner class will be used.16  *17  * @return the initial value for this thread-local18  */19 protected T initialValue() {20     return null;21 }

? ? ? ?返回當(dāng)前線程對應(yīng)的ThreadLocal的初始值。當(dāng)當(dāng)前線程是通過get()方法第一次對ThreadLocal進(jìn)行訪問時,該方法將會被調(diào)用,除非當(dāng)前線程之前調(diào)用過set()方法,在這種情況下initialValue()方法將不會被當(dāng)前線程所調(diào)用。一般而言,該方法最多只會被每個線程調(diào)用一次,除非隨后在當(dāng)前線程中調(diào)用remove()方法,然后調(diào)用get()方法。該實現(xiàn)會簡單地返回null;如果程序員希望ThreadLocal擁有一個初始值,而不是null,ThreadLocal需要定義一個子類,并且在子類中重寫initialValue()方法。比較典型的做法是使用一個匿名內(nèi)部類。該方法由protected修飾,可見其這樣設(shè)計通常是為了供用戶重寫,從而自定義初始值。后面會再通過實例來演示該方法的使用。

?

5、ThreadLocal工作機(jī)制

? ? ? ?ThreadLocal使用起來非常簡單,但它是如何實現(xiàn)為每一個Thread保存一份獨立的數(shù)據(jù)的呢?我們先結(jié)合實例3.1來看set()方法都做了些什么:

1 //=========ThreadLocal=======源碼5.12 public void set(T value) {3     Thread t = Thread.currentThread();4     ThreadLocalMap map = getMap(t);5     if (map != null)6         map.set(this, value);7     else8         createMap(t, value);9 }

? ? ? ?首先就是獲取當(dāng)前的線程,然后根據(jù)當(dāng)前線程來獲取一個ThreadLocalMap,如果map不為null,就往map中插入指定值,注意這的key是ThreadLocal實例;如果map為null,就創(chuàng)建一個map??纯吹?行g(shù)etMap(t)做了啥:

 1 //=========ThreadLocal=======源碼5.2 2 /** 3  * Get the map associated with a ThreadLocal.  4  * ...... 5  */ 6 ThreadLocalMap getMap(Thread t) { 7     return t.threadLocals; 8 } 9 10 /**11  * ThreadLocalMap is a customized hash map suitable only for12  * maintaining thread local values......13  */14 static class ThreadLocalMap {15      ......16 }17 18 //==========Thread========19 ThreadLocal.ThreadLocalMap threadLocals = null;

? ? ? ?getMap()返回的是指定線程(也就是當(dāng)前線程)的threadLocals變量,這個變量是ThreadLocal.ThreadLocalMap類型的,而ThreadLocalMap是一個僅適用于維護(hù)線程本地變量值的自定義的HashMap。簡單來說,就是返回當(dāng)前線程下的一個自定義HashMap。

? ? ? ?下面我抽取了ThreadLocalMap的部分代碼,先來總體上認(rèn)識它(這里我們不需要讀懂其中的每一行代碼,知道它里面主要做了哪些事就可以了):

  1 //=========源碼5.3========  2 static class ThreadLocalMap {  3   4     static class Entry extends WeakReference<ThreadLocal<?>> {  5         /** The value associated with this ThreadLocal. */  6         Object value;  7   8         Entry(ThreadLocal<?> k, Object v) {  9             super(k); 10             value = v; 11         } 12     } 13  14     /** 15      * The initial capacity -- MUST be a power of two. 16      */ 17     private static final int INITIAL_CAPACITY = 16; 18  19     /** 20      * The table, resized as necessary. 21      * table.length MUST always be a power of two. 22      */ 23     private Entry[] table; 24  25     /** 26      * The number of entries in the table. 27      */ 28     private int size = 0; 29  30     /** 31      * The next size value at which to resize. 32      */ 33     private int threshold; // Default to 0 34  35     /** 36      * Set the resize threshold to maintain at worst a 2/3 load factor. 37      */ 38     private void setThreshold(int len) { 39         threshold = len * 2 / 3; 40     } 41      42     ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) { 43         table = new Entry[INITIAL_CAPACITY]; 44         int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); 45         table[i] = new Entry(firstKey, firstValue); 46         size = 1; 47         setThreshold(INITIAL_CAPACITY); 48     } 49      50     /** 51      * Get the entry associated with key. 52      * ...... 53      */ 54     private Entry getEntry(ThreadLocal<?> key) { 55         int i = key.threadLocalHashCode & (table.length - 1); 56         Entry e = table[i]; 57         if (e != null && e.get() == key) 58             return e; 59         else 60             return getEntryAfterMiss(key, i, e); 61     } 62  63     /** 64      * Set the value associated with key. 65      * ...... 66      */ 67     private void set(ThreadLocal<?> key, Object value) { 68  69         // We don't use a fast path as with get() because it is at 70         // least as common to use set() to create new entries as 71         // it is to replace existing ones, in which case, a fast 72         // path would fail more often than not. 73  74         Entry[] tab = table; 75         int len = tab.length; 76         int i = key.threadLocalHashCode & (len-1); 77  78         for (Entry e = tab[i]; 79              e != null; 80              e = tab[i = nextIndex(i, len)]) { 81             ThreadLocal<?> k = e.get(); 82  83             if (k == key) { 84                 e.value = value; 85                 return; 86             } 87  88             if (k == null) { 89                 replaceStaleEntry(key, value, i); 90                 return; 91             } 92         } 93  94         tab[i] = new Entry(key, value); 95         int sz =   size; 96         if (!cleanSomeSlots(i, sz) && sz >= threshold) 97             rehash(); 98     } 99 100     /**101      * Remove the entry for key.102      */103     private void remove(ThreadLocal<?> key) {104         Entry[] tab = table;105         int len = tab.length;106         int i = key.threadLocalHashCode & (len-1);107         for (Entry e = tab[i];108              e != null;109              e = tab[i = nextIndex(i, len)]) {110             if (e.get() == key) {111                 e.clear();112                 expungeStaleEntry(i);113                 return;114             }115         }116     }117 118     /**119      * Double the capacity of the table.120      */121     private void resize() {122        ......123     }124 }
View Code

? ? ? ?這里面維護(hù)了一個Entry[] table數(shù)組,初始容量為16,當(dāng)數(shù)據(jù)超過當(dāng)前容量的2/3時,就開始擴(kuò)容,容量增大一倍。每一個Entry的K為ThreadLocal對象,V為要存儲的值。每一個Entry在數(shù)組中的位置,是根據(jù)其K(即ThreadLocal對象)的hashCode & (len - 1)來確定,如第44行所示,這里K的hashCode是系統(tǒng)給出的一個算法計算得到的。如果碰到K的hashCode值相同,即hash碰撞的場景,會采用尾插法形成鏈表。當(dāng)對這個map進(jìn)行set,get,remove操作的時候,也是通過K的hashCode來確定該Entry在table中的位置的,采用hashCode來查找數(shù)據(jù),效率比較高。這也是HashMap底層實現(xiàn)的基本原理,如果研究過HashMap源碼,這段代碼就應(yīng)該比較容易理解了。

? ? ? ?繼續(xù)看源碼5.1,第一次調(diào)用的時候,顯然map應(yīng)該是null,就要執(zhí)行第8行createMap了,

1 //==========ThreadLocal=========源碼5.42 void createMap(Thread t, T firstValue) {3     t.threadLocals = new ThreadLocalMap(this, firstValue);4 }

? ? ? ?結(jié)合ThreadLocalMap源碼第41行的構(gòu)造方法,就清楚了這個方法創(chuàng)建了一個ThreadLocalMap對象,并存儲了一個Entry<當(dāng)前的ThreadLocal對象,value>。此時,在當(dāng)前的線程下?lián)碛辛艘粋€ThreadLocalMap,這個ThreadLocalMap中維護(hù)了一個容量為16的table,table中存儲了一個以當(dāng)前的ThreadLocal對象為K,value值為V的Entry。Thread、ThreadLocalMap、ThreadLocal、Entry之間的關(guān)系可以表示為下圖:

?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖5.1

? ? ? ?而如果當(dāng)前Thread的map已經(jīng)存在了,源碼5.1就會執(zhí)行第6行了,進(jìn)而執(zhí)行ThreadLocalMap中的set方法。結(jié)合前面對ThreadLocalMap的介紹,想必這個set方法也容易理解了,大致過程是:

? ? 1)根據(jù)Thread找到map;

? ? 2)通過傳入的this(即ThreadLocal對象),得到hashCode;

? ? 3)根據(jù)hashCode & (len - 1)確定對應(yīng)Entry在table中的位置;

? ? 4)如果該Entry存在,則替換Value,否則新建(ThreadLocalMap源碼第78~92行表示在具有相同hashCode的Entry鏈表上找到對應(yīng)的Entry,這和hash碰撞有關(guān))。

?

? ? ? ?在調(diào)用ThreadLocal的get方法時又做了什么呢?看看其源碼:

 1 //=========ThreadLocal======源碼5.5 2 public T get() { 3     Thread t = Thread.currentThread(); 4     ThreadLocalMap map = getMap(t); 5     if (map != null) { 6         ThreadLocalMap.Entry e = map.getEntry(this); 7         if (e != null) { 8             @SuppressWarnings("unchecked") 9             T result = (T)e.value;10             return result;11         }12     }13     return setInitialValue();14 }

? ? ? ?現(xiàn)在,第12行及以前的代碼應(yīng)該很容易理解了,結(jié)合ThreadLocalMap中的get源碼,我們再梳理一下:

? ? 1)根據(jù)Thread找到自己的map;

? ? 2)在map中通過this(即ThreadLocal對象)得到hashCode;

? ? 3)通過hashCode & (len-1)找到對應(yīng)Entry在table中的位置;

? ? 4)返回Entry的value。

? ? ? ?而如果map為null,或者在map中找到的Entry為null,那么就執(zhí)行第20行了。

 1 //==========ThreadLocal========源碼5.6 2 private T setInitialValue() { 3     T value = initialValue(); 4     Thread t = Thread.currentThread(); 5     ThreadLocalMap map = getMap(t); 6     if (map != null) 7         map.set(this, value); 8     else 9         createMap(t, value);10     return value;11 }12 13 protected T initialValue() {14     return null;15 }
第13行的initialValue()方法,前面介紹過,可以讓子類重寫,即給ThreadLocal指定初始值;如果沒有重寫,那返回值就是null。第4~9行前面也介紹過了,使用或者創(chuàng)建map來存入該值。

最后還一個remove()方法

1 //======ThreadLocal======2 public void remove() {3     ThreadLocalMap m = getMap(Thread.currentThread());4     if (m != null)5         m.remove(this);6 }

結(jié)合ThrealLocalMap中的remove方法,完成對ThreadLocal值的刪除。其大致流程為:

? ? 1)根據(jù)當(dāng)前Thread找到其map;

? ? 2)根據(jù)ThreadLocal對象得到hashCode;

? ? 3)通過hashCode & (len -1)找到在table中的位置;

? ? 4)在table中查找對應(yīng)的Entry,如果存在則刪除。

?

總結(jié):

? ? ? ?通過對提供的4個接口方法的分析,我們應(yīng)該就能清楚了,ThreadLocal之所以能夠為每一個線程維護(hù)一個副本,是因為每個線程都擁有一個map,這個map就是每個線程的專屬空間。也就是存在下面的關(guān)系圖(不用懷疑,該圖和圖5.1相比,只是少了容量大小):

結(jié)合這一節(jié)對ThreadLocal機(jī)制的介紹,實例3.1執(zhí)行后的就存在如下的數(shù)據(jù)結(jié)構(gòu)了:

?

?

6、ThreadLocal在Looper中的使用

? ? ? ?ThreadLocal在系統(tǒng)源碼中有很多地方使用,最典型的地方就是Handler的Looper中了。這里結(jié)合Looper中的源碼,來了解一下ThreadLocal在系統(tǒng)源碼中的使用。

? ? ? ?我們知道,在一個App進(jìn)程啟動的時候,會在ActiivtyThread類的main方法,也就是App的入口方法中,會為主線程準(zhǔn)備一個Looper,如下代碼所示:

1 //======ActivityTread======源碼6.12 public static void main(String[] args) {3       ......4       Looper.prepareMainLooper();5       ......6 }

而在子線程中實例Handler的時候,總是需要顯示調(diào)用Looper.prepare()方法來為當(dāng)前線程生成一個Looper對象,以及通過Looper.myLooper()來得到自己線程的Looper來傳遞給Handler。

Looper中相關(guān)的關(guān)鍵源碼如下:

 1 //==========Looper========源碼6.2 2  3 // sThreadLocal.get() will return null unless you've called prepare(). 4 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); 5 private static Looper sMainLooper; 6  7 /** 8  * Initialize the current thread as a looper, marking it as an 9  * application's main looper. The main looper for your application10  * is created by the Android environment, so you should never need11  * to call this function yourself.  See also: {@link #prepare()}12  */13 public static void prepareMainLooper() {14     prepare(false);15     synchronized (Looper.class) {16         if (sMainLooper != null) {17             throw new IllegalStateException("The main Looper has already been prepared.");18         }19         sMainLooper = myLooper();20     }21 }22 23 /**24  * Return the Looper object associated with the current thread.  Returns25  * null if the calling thread is not associated with a Looper.26  */27 public static @Nullable Looper myLooper() {28     return sThreadLocal.get();29 }30 31 /** Initialize the current thread as a looper.32   * ......33   */34 public static void prepare() {35     prepare(true);36 }37 private static void prepare(boolean quitAllowed) {38     if (sThreadLocal.get() != null) {39         throw new RuntimeException("Only one Looper may be created per thread");40     }41     sThreadLocal.set(new Looper(quitAllowed));42 }43 44 /**45  * Returns the application's main looper, which lives in the main thread of the application.46  */47 public static Looper getMainLooper() {48     synchronized (Looper.class) {49         return sMainLooper;50     }51 }

我們可以看到不少ThreadLocal的影子,Looper也正是通過ThreadLocal來為每個線程維護(hù)一份Looper實例的。通過我們前文的介紹,這里應(yīng)該能夠輕而易舉理解其中的運作機(jī)制了吧,這里就再不啰嗦了。

?

7、實踐是檢驗真理的唯一標(biāo)準(zhǔn)

? ? ? ? 前面介紹了ThreadLocal提供的四個接口,以及詳細(xì)講解了它的工作原理?,F(xiàn)在我們將實例3.1做一些修改,將各個接口的功能都包含進(jìn)來,并稍微增加一點復(fù)雜度,如果能夠看懂這個實例,就算是真的理解ThreadLocal了。

 1 //=========實例7.1======= 2 private ThreadLocal<String> mStrThreadLocal = new ThreadLocal<String>() { 3     @Override 4     protected String initialValue() { 5         Log.i("threadlocaldemo", "initialValue"); 6         return "initName"; 7     } 8 }; 9 private ThreadLocal<Long> mLongThreadLocal = new ThreadLocal<>();10 private void testThreadLocal() throws InterruptedException {11     mStrThreadLocal.set("main-thread");12     mLongThreadLocal.set(Thread.currentThread().getId());13     Log.i("threadlocaldemo", "result-1:name="   mStrThreadLocal.get()   ";id="   mLongThreadLocal.get());14     Thread thread_1 = new Thread() {15         @Override16         public void run() {17             super.run();18             mStrThreadLocal.set("thread_1");19             mLongThreadLocal.set(Thread.currentThread().getId());20             Log.i("threadlocaldemo", "result-2:name="   mStrThreadLocal.get()   ";id="   mLongThreadLocal.get());21         }22     };23     thread_1.start();24     //該句表示thread_1執(zhí)行完后才會繼續(xù)執(zhí)行25     thread_1.join();26     Thread thread_2 = new Thread() {27         @Override28         public void run() {29             super.run();30             Log.i("threadlocaldemo", "result-3:name="   mStrThreadLocal.get()   ";id="   mLongThreadLocal.get());31         }32     };33     thread_2.start();34     //該句表示thread_2執(zhí)行完后才會繼續(xù)執(zhí)行35     thread_2.join();36     mStrThreadLocal.remove();37     Log.i("threadlocaldemo", "result-4:name="   mStrThreadLocal.get()   ";id="   mLongThreadLocal.get());38 }

在主線程中運行該方法,執(zhí)行結(jié)果為:

1 12-14 16:25:40.662 4844-4844/com.example.demos I/threadlocaldemo: result-1:name=main-thread;id=22 12-14 16:25:40.668 4844-5351/com.example.demos I/threadlocaldemo: result-2:name=thread_1;id=9263 12-14 16:25:40.669 4844-5353/com.example.demos I/threadlocaldemo: initialValue4 12-14 16:25:40.669 4844-5353/com.example.demos I/threadlocaldemo: result-3:name=initName;id=null5 12-14 16:25:40.669 4844-4844/com.example.demos I/threadlocaldemo: initialValue6 12-14 16:25:40.669 4844-4844/com.example.demos I/threadlocaldemo: result-4:name=initName;id=2

此時存在的數(shù)據(jù)結(jié)構(gòu)為:

? ? ? ?對于這份log和數(shù)據(jù)結(jié)構(gòu)圖,這里就不再一一講解了,如果前面都看懂了,這些都是小菜一碟。

?

結(jié)語

? ? ? ?對ThreadLocal的講解這里就結(jié)束了,能讀到這里,也足以說明你是人才,一定前途無量,祝你好運,早日走上人生巔峰!

? ? ? ?由于經(jīng)驗和水平有限,有描述不當(dāng)或不準(zhǔn)確的地方,還請不吝賜教,謝謝!

?

來源:https://www.icode9.com/content-4-597051.html
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
徹底理解ThreadLocal
Java 多線程同步問題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)
ThreadLocal原理及使用示例
Java線程(篇外篇):線程本地變量ThreadLocal
深入JDK源碼之ThreadLocal類
深入分析ThreadLocal
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服