標籤:clu for迴圈 creat size 執行個體 不為 conf 引入 相等
一. Integer1.引子
在開始之前,我還是需要吐槽下自己,我是真的很菜!
- 他問:**兩個Integer對象==比較是否相等?
- 我答:對象==比較,是引用比較,不相等!
- 他問:IntegerCache這個用來幹什嗎?
- 我答:......,我不是很清楚!!!
從這裡可以看出,我是真的很水!!
基於這些原因還有其他的等等,我開始寫博文,開始寫踩過的坑!
2.IntegerCache
在介紹這個緩衝之前,先來認知下Integer。java中,int是基本的數實值型別,表示整型;Integer是其對象的表示,是int的封裝類。封裝類在Jdk1中就存在,但是為了更方便的使用Integer,在Java SE5中引入自動封裝和自動拆箱的機制,這裡不再贅述,可以移步至深入剖析Java中的裝箱和拆箱。
Java SE5可以說是java版本迭代過程中裡程碑版本。為了減少大量建立Integer的開銷、提高效能,採用享元模式,引入Integer執行個體緩衝,將-128至127範圍數值的Integer執行個體緩衝在記憶體中,這裡的緩衝就是使用Integer中的輔助性的私人IntegerCache靜態類實現。
先看下如何擷取緩衝的-128至127範圍的Integer執行個體,這裡的範圍可以通過JVM啟動參數修改,後面會講述
- 可以通過使用靜態valueOf方法擷取 // api調用
- 可以使用自動封裝機制擷取,如:
Integer a = 100; // autoboxing
這裡基於Java SE8,再來看下IntegerCache的實現:
/** * Cache to support the object identity semantics of autoboxing for values between * -128 and 127 (inclusive) as required by JLS. * * The cache is initialized on first usage. The size of the cache * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option. * During VM initialization, java.lang.Integer.IntegerCache.high property * may be set and saved in the private system properties in the * sun.misc.VM class. */private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {}}
從java docs中可以看出,該類是為了支援對-128至127範圍數值自動封裝的執行個體進行緩衝。
在第一次使用時緩衝被初始化,緩衝的大小可以通過JVM參數-XX:AutoBoxCacheMax=size控制,IntegerCache的high可以通過在JVM啟動時設定系統屬性變數java.lang.Integer.IntegerCache.high,以達到更強的靈活性。IntegerCache在執行類構造器初始化時,執行靜態語句塊,利用for迴圈從low開始不斷自加加,然後放入cache數組中。
選擇-128至127範圍,是因為這個範圍內的數值使用更普遍!
介紹到這裡,相信已經不難看出我的回答是多麼搞笑,我坐井觀天的還以為自己是正確的!
說到這裡,我又有些感慨了,昨晚看了集火影,剛好是自來也和佩恩的對話,佩恩對曾經的師傅自來也的一席話,雖然是偏執的,但是無可否認的確是對的。
佩恩把自己稱為神,將自來也視作為凡人,說凡人的認知具有局限性,活在狹小的空間內自認為自己認識都是對的,殊不知從神的角度考慮,凡人的那些認知都是錯誤和愚蠢的。
這裡旨在單純思考佩恩這些話在我們現實生活中的含義:的確,在我們認知有限的時候,以為Integer兩個對象==比較,應該是不等的,殊不知因為技術掌握有限。
跑題了,引入一段故事,主要是想銘刻下,吸取教訓:不要把事物看做是理所當然,要多多思考其本質和原理;不要妄下結論,小心求證!
不僅是Integer,Short、Byte、Long、Char都具有相應的Cache。但是Byte、Short、Long的Cache有固定範圍:-128至127;Char的Cache:0至127。
引用
理解Java Integer的緩衝策略
二. ThreadLocal
我這裡不再贅述ThreadLocal是什麼、解決什麼問題、實現原理、應用情境等,網上博文非常豐富,可移步至深入剖析ThreadLocal。
這裡主要是分析下ThreadLocal在父子線程中共用的問題。
ThreadLocal不提供對子線程共用父線程的ThreadLocal中儲存的value的支援,ThreadLocal的get方法返回與當前線程有關的ThreadLocalMap中的key/value,如:
/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ThreadLocal.ThreadLocalMap threadLocals = null;
每個線程在建立的時候,都會初始化ThreadLocalMap的Null 參考。 子線程在建立時ThreadLocaMap是null,所以不共用父線程的ThreadLocalMap中key/value。
但是有很多時候,實際需求需要共用父線程的一些狀態值。 這種情況,java也對此提供了支援,只能說設計者們的腦洞大開。
java中引入另一個InheritableThreadLocal類對此提供支援,類名給出了用途的最好表示:可繼承的ThreadLocal!
/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ThreadLocal.ThreadLocalMap threadLocals = null;
同理,每個線程在建立的時候都會初始化InheritableThreadLocal
的引用,然後線上程執行初始化的生命週期階段時,對該變數進行初始化操作,如:
if (parent.inheritableThreadLocals != null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
線程的初始化周期中,首先判斷父線程的ThreadLocal是否為空白,如果不為空白則根據父線程的inheritableThreadLocals建立子線程的inheritableThreadLocals。
InheritableThreadLocal的實現也非常簡單:
- childValue: 計運算元線程的初始化值,從這個方法中可以知道,子線程使用的是父線程中的value,並不是拷貝,如果需要使用副本拷貝,可以繼承重寫
- getMap: 返回當前線程持有的inheritableThreadLocals
- createMap: 如果當前線程的inheritableThreadLocals是空,則建立一個
以上三個api都是重寫ThreadLocal的。
Java中Integer和ThreadLocal