java threadlocal 缺点_Java的ThreadLocal如何在后台实现?
小編典典
這里的所有答案都是正確的,但是有些令人失望,因為它們多少掩蓋了聰明ThreadLocal的實現(xiàn)是多么的明智。我只是在尋找源代碼,ThreadLocal并且對它的實現(xiàn)方式印象深刻。
天真的實現(xiàn)
如果我要求您ThreadLocal在javadoc中描述的給定API的基礎(chǔ)上實現(xiàn)一個類,該怎么辦?最初的實現(xiàn)可能是ConcurrentHashMap使用Thread.currentThread()作為其密鑰。這樣會很好地工作,但確實有一些缺點。
線程爭用- ConcurrentHashMap是一個非常聰明的類,但是它最終仍必須處理防止多個線程以任何方式破壞它,并且如果不同的線程有規(guī)律地命中它,將會降低速度。
即使在線程完成并且可以進行GC處理后,它仍永久保持指向線程和對象的指針。
GC友好的實現(xiàn)
好的,再試一次,讓我們使用弱引用來處理垃圾回收問題。處理WeakReferences可能會造成混淆,但是使用像這樣構(gòu)建的地圖應(yīng)該足夠了:
Collections.synchronizedMap(new WeakHashMap())
或者,如果我們使用的是番石榴(應(yīng)該是!):
new MapMaker().weakKeys().makeMap()
這意味著一旦沒有其他人抓住線程(暗示線程已完成),就可以對鍵/值進行垃圾收集,這是一種改進,但仍無法解決線程爭用問題,這意味著到目前為止,我們ThreadLocal還不是全部令人贊嘆的一堂課。此外,如果有人決定在Thread完成后保留對象,那么就永遠不會對它們進行GC處理,因此即使我們的對象現(xiàn)在在技術(shù)上無法到達,也不會對其進行GC處理。
聰明的實現(xiàn)
我們一直在考慮ThreadLocal將線程映射為值,但是也許這實際上并不是正確的思考方式。與其將其視為從Threads到每個ThreadLocal對象中的值的映射,不如將其視為ThreadLocal對象到
每個Thread中的
值的映射怎么辦?如果每個線程都存儲了該映射,而ThreadLocal僅提供了該映射的一個不錯的接口,我們可以避免以前實現(xiàn)中的所有問題。
一個實現(xiàn)看起來像這樣:
// called for each thread, and updated by the ThreadLocal instance
new WeakHashMap()
此處無需擔(dān)心并發(fā)性,因為只有一個線程將訪問此映射。
Java開發(fā)人員在這里比我們有一個主要優(yōu)勢-他們可以直接開發(fā)Thread類并向其添加字段和操作,而這正是他們所做的。
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
正如評論所暗示的,確實是ThreadLocal對象為此跟蹤的所有值的私有包映射Thread。的實現(xiàn)ThreadLocalMap不是WeakHashMap,而是遵循相同的基本協(xié)定,包括通過弱引用來持有其密鑰。
ThreadLocal.get() 然后實現(xiàn)如下:
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
而ThreadLocal.setInitialValue()像這樣:
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;
}
本質(zhì)上, 在此線程中
使用地圖可以容納我們所有的ThreadLocal對象。這樣,我們永遠不必擔(dān)心其他線程中的值(ThreadLocal字面上只能訪問當(dāng)前線程中的值),因此沒有并發(fā)問題。此外,一旦Thread完成,其映射將自動進行GC處理,并且將清除所有本地對象。即使將Thread其保留,ThreadLocal對象也會被弱引用保留,并且一旦ThreadLocal對象超出范圍,就可以將其清除。
不用說,這個實現(xiàn)給我留下了深刻的印象,它很好地解決了很多并發(fā)問題(可以利用作為核心Java的一部分,但這是可以原諒的,因為它是一個非常聰明的類),并且允許快速和對僅一次需要一個線程訪問的對象的線程安全訪問。
tl; dr ThreadLocal的實現(xiàn)非常酷,并且比您乍看之下要快/聰明得多。
如果您喜歡這個答案,您可能也會喜歡我(不那么詳細)的討論ThreadLocalRandom。
2020-09-15
總結(jié)
以上是生活随笔為你收集整理的java threadlocal 缺点_Java的ThreadLocal如何在后台实现?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑一直显示等待卸载(为什么电脑一直显示
- 下一篇: java中iscontinue意思_Ja