<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
1.ThreadLocal 執行緒變數,和當前執行緒繫結的,只儲存當前執行緒的變數,對於其他執行緒是隔離的,是存取不到裡面的資料的。
2.在Looper中使用到了ThreadLocal,建立了一個Looper是儲存到了ThreadLocal中。
//這裡用到了泛型,ThreadLocal中只儲存Looper物件。 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { //保證Looper只被建立一次。 throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
看下sThreadLocal.set()方法是如何儲存資料的。
先拿到當前執行緒,然後在拿到該執行緒的ThreadLocalMap成員變數,然後儲存到這個map中,
key就是建立的ThreadLocal物件,value就是傳進來的value。
public void set(T value) { //拿到當前執行緒 Thread t = Thread.currentThread(); //得到一個map ThreadLocalMap map = getMap(t); if (map != null){ // 這個map是以當前物件為key的,這個this就是 ThreadLocal的範例 sThreadLocal map.set(this, value); }else{ createMap(t, value); } }
//getMap 是從Thread中拿到了一個threadLocals變數,是ThreadLocal.ThreadLocalMap 的範例。 //儲存的資料也是存在了這個map中,這也就是為什麼ThreadLocal是和執行緒繫結的,對其他執行緒來說是隔離的原因所在。 ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
1)儲存資料,如果map不為空的情況。走上面if判斷的第一個分支。這個儲存方式和HashMap類似
private void set(ThreadLocal<?> key, Object value) { Entry[] tab = table; int len = tab.length; // 計算出key在集合中的索引,index int i = key.threadLocalHashCode & (len-1); //開始遍歷整個陣列, //取出索引為i的Entry,如果不為空,取出下一個,進行遍歷 for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { ThreadLocal<?> k = e.get(); //如果取出的k和傳進來的key一致,則把新的值存起來。 if (k == key) { e.value = value; return; } //直到取出最有一個,k==null則進行儲存。 if (k == null) { replaceStaleEntry(key, value, i); return; } } //如果索引i的位置,沒有Entry,則把傳進來的key和value儲存在這個位置。 tab[i] = new Entry(key, value); int sz = ++size; //如果大於閾值了,則進行擴容 if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); }
2)儲存資料,如果map為空的情況。則建立ThreadLocalMap,並賦值給當前執行緒t。
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) { //建立一個大小為16的陣列 table = new Entry[INITIAL_CAPACITY]; //計算得到的i是陣列的角標。可以參考hashMap原始碼分析 int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); //賦值,儲存資料 table[i] = new Entry(firstKey, firstValue); size = 1; //擴容的閾值 setThreshold(INITIAL_CAPACITY); }
3.再看看ThreadLocal是如何取值的。
也是先拿到當前執行緒t,然後通過t拿到他的成員變數ThreadLocalMap。
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); //如果map不為空,則從map中取值 if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } //如果map為空 return setInitialValue(); }
1)如果map不為空則從map中取值。
//如果map不為空 private Entry getEntry(ThreadLocal<?> key) { //拿到key對應的索引 int i = key.threadLocalHashCode & (table.length - 1); //從陣列中拿到Entry Entry e = table[i]; if (e != null && e.get() == key){如果key一樣直接返回 return e; }else{//如果不一致則開始遍歷 return getEntryAfterMiss(key, i, e); } }
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) { Entry[] tab = table; int len = tab.length; while (e != null) { ThreadLocal<?> k = e.get(); if (k == key) return e; if (k == null) expungeStaleEntry(i); else i = nextIndex(i, len); e = tab[i]; } return null; }
2)如果在get時,得到的map是空的,則這個時候需要初始化
//如果map為空,則呼叫這個方法,initialValue由使用者去實現。 private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
//下面是Choreographer中的例子: private static final ThreadLocal<Choreographer> sThreadInstance = new ThreadLocal<Choreographer>() { @Override protected Choreographer initialValue() { Looper looper = Looper.myLooper(); if (looper == null) { throw new IllegalStateException("The current thread must have a looper!"); } Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP); if (looper == Looper.getMainLooper()) { mMainInstance = choreographer; } return choreographer; } };
總結ThreadLocal是通過 ThreadLocalMap 進行資料的儲存的。而這個ThreadLocalMap物件是通過
獲取到當前執行緒,並從當前執行緒中拿到的。所以ThreadLocalMap只儲存本執行緒的資料,做到了執行緒隔離。
ThreadLocalMap存資料的key是ThreadLocal物件本身。 map.set(this, value);
如果想要給ThreadLocalMap中存更多的資料,則需要建立多個物件。
到此這篇關於Java執行緒變數ThreadLocal原始碼分析的文章就介紹到這了,更多相關Java ThreadLocal內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45