一、Integer類的緩存機制
我們查看Integer的源碼,就會發現里面有個靜態內部類。
public static Integer valueOf(int i) { assert IntegerCache.high >= 127; //當前值在緩存數組區間段,則直接返回該緩存值 if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; //否則創建新的Integer實例 return new Integer(i); } private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; //IntegerCache初始化時,緩存數值為-128-127的Integer實例(默認是從-128到127)。 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) { 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); } high = h; cache = new Integer[(high - low) + 1]; int j = low; //填充緩存數組 for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); } private IntegerCache() {} }
該類的作用是將數值等於-128-127(默認)區間的Integer實例緩存到cache數組中。通過valueOf()方法很明顯發現,當再次創建值在-128-127區間的Integer實例時,會復用緩存中的實例,也就是直接指向緩存中的Integer實例。
(注意:這里的創建不包括用new創建,new創建對象不會復用緩存實例,通過情景3的運行結果就可以得知)
二、其它具有緩存機制的類
實際上不僅僅Integer具有緩存機制,Byte、Short、Long、Character都具有緩存機制。來看看Long類中的緩存類
private static class LongCache { private LongCache(){} static final Long cache[] = new Long[-(-128) + 127 + 1]; static { for(int i = 0; i < cache.length; i++) cache[i] = new Long(i - 128); } }
ByteCache用於緩存Byte對象,ShortCache用於緩存Short對象,LongCache用於緩存Long對象,CharacterCache用於緩存Character對象。這些類都有緩存的范圍,其中Byte,Short,Integer,Long為 -128 到 127,Character范圍為 0 到 127。除了 Integer 可以通過參數改變范圍外,其它的都不行。
面試題
面試題1:
//情景1 Integer c = 128; Integer d = 128; System.out.println(c == d);//false //情景2 Integer a = 1; Integer b = 1; System.out.println(a == b);//true。b.intValue() //情景3 Integer e = new Integer(1); Integer f = new Integer(1); System.out.println(e == f);//false
面試題2:
//情景4 int a = 1; Integer b = Integer.valueOf(1); Integer c = new Integer(1); System.out.println(a == b);//true System.out.println(a == c);//true
分析:a是基本類型,b和c是引用類型,兩者進行比較時有一個拆箱的過程,也就是會默認調用b和c的intValue()方法。
//拆箱 public int intValue() { return value; }
最終比較的是基本類型的值,自然是相等的。
面試題3:
//代碼來源於《深入理解Java虛擬機》第4章4.3.1 P121。 public class SynAddRunnable implements Runnable { int a, b; public SynAddRunnable(int a, int b) { this.a = a; this.b = b; } @Override public void run() { synchronized (Integer.valueOf(a)) { synchronized (Integer.valueOf(b)) { System.out.println(a + b); } } } public static void main(String[] args) { for (int i = 0; i < 100; i++) { new Thread(new SynAddRunnable(1, 2)).start(); new Thread(new SynAddRunnable(2, 1)).start(); } } }
上面這段程序會發生死鎖。造成死鎖的原因:[-128,127]之間的數字會被緩存,而Integer.valueOf()會返回緩存的對象。因此代碼中200次for循環實際上總共只創建了兩個對象,當線程A持有Integer.valueOf(1)時,如果線程B持有Integer.valueOf(2),則就會出現死鎖,屬於動態鎖順序死鎖。
總結
1.具有緩存機制的類?
Byte、Short、Integer、Long、Character都具有緩存機制。緩存工作都是在靜態塊中完成,在類生命周期(loading verify prepare resolving initial using unload)的初始化階段執行。
2.緩存范圍?
Byte,Short,Integer,Long為 -128 到 127
Character范圍為 0 到 127
除了Integer可以指定緩存范圍,其它類都不行。Integer的緩存上界high可以通過jvm參數-XX:AutoBoxCacheMax=size指定,取指定值與127的最大值並且不超過Integer表示范圍,而下界low不能指定,只能為-128。