摘要:作為條件變量的的不僅可以認為內嵌了一把鎖,還內嵌了一個條件變量。操作條件變量的函數將當前線程在條件變量上阻塞,一般是為了等待其他線程的某件事情執行完成。其它裝箱類其它裝箱類的代碼這里就不分析了。重點關注下各裝箱類的緩存范圍。
jdk源碼讀到現在這里,重要的集合類也讀了一部分了。
集合類再往下讀的話,就要涉及到兩個方向。
第一,是比較典型的但是不常用的數據結構,這部分我準備將數據結構復習、回顧后再繼續閱讀。
第二,是并發相關的集合,這部分我準備留到和并發相關的類一起閱讀。
所以,今天就讀些輕松的。
Object 作為單根繼承的Objectjava的對象系統設計是采用單根繼承,所有的對象往上追溯,Object都是它們共同的祖先。
有了這個假設,我忽然想起java中一個有趣的事實:
Listlist = new ArrayList (); list.toString();
這段代碼能正常編譯、運行嗎?經驗告訴我,當然可以。
可是從類型系統的角度仔細思考,list引用的類型為List
然而,List接口中并沒有toString方法,為什么能調用?
這是由于,在java中,會讓接口類型也擁有Object的所有方法。一個接口對象,也是一個Object對象。因為單根繼承這一總體設計,所以這樣設計接口是合理的。
這里有關于該問題的有趣討論,所以這里就不詳細展開了。
在java中,除了最基本的單根繼承的祖先類之外,Object還內置了很多機制。如:
Object o = new Object(); synchronized(o) { /* ... */ }
在其它語言中,鎖這一機制都是標準庫中提供的函數,成對使用。一個lock函數用于獲取鎖,一個release函數函數用于釋放鎖。
然而,java直接將鎖機制作為語法的一部分,還給它一個專屬關鍵字synchronized。每個Object對象,都內嵌了一個鎖。java稱之監視器鎖。
這樣設計有什么好處呢?一種觀點是,將鎖機制內置為語法的一部分,有利于jvm對其進行深度優化提升性能,如java的鎖升級機制。
作為條件變量的Objectjava的Object不僅可以認為內嵌了一把鎖,還內嵌了一個條件變量。操作條件變量的函數:
public final native void notify(); public final native void notifyAll(); public final native void wait(long timeout) throws InterruptedException;
wait將當前線程在條件變量上阻塞,一般是為了等待其他線程的某件事情執行完成。當其他線程的事情執行完成后,在條件變量上調用notify或notifyAll來喚醒阻塞的線程。
可以看到,這三個方法都是native,jvm原生實現。
wait還有兩個重載形式:
public final void wait() throws InterruptedException { wait(0); } public final void wait(long timeout, int nanos) throws InterruptedException { if (timeout < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException( "nanosecond timeout value out of range"); } if (nanos > 0) { timeout++; } wait(timeout); }
比較有意思的是第二個。
原生實現的wait(long timeout),只能設置毫秒級別的超時時間。但是這個wait(long timeout, int nanos)卻能設置納秒級別的超時時間。怎么實現的?
if (nanos > 0) { timeout++; }
笑哭了。。。。難道是我下載的jdk平臺不對?
hashCode、equals、toStringObject類提供了這三個函數的默認實現。來看一下:
public native int hashCode(); public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } public boolean equals(Object obj) { return (this == obj); }
可以看到,hashCode的默認方法是原生實現,到底是不是指針不清楚。
equals方法的默認實現僅僅簡單比較了是否為同一引用。
toString()方法打印出的是類名及十六進制的hash值。
裝箱拆箱裝箱拆箱機制的存在的原因是:
java中的泛型是類型擦除,類似集合等泛型類中實際存放的必須是Object的子類,也即引用類型。
java的8種基本類型都是值類型,不是對象。因此無法直接放入泛型類對象中。
為了解決這個沖突,只好設計一組對象,中間包裹基本類型,并且語法層次內建裝箱類與基本類型的自動轉換機制,也即自動裝箱拆箱。
下面以Integer為例分析裝箱拆箱類的源碼。
Integer大致看一下Integer中的組成。可以發現有三個不同的部分:
Integer類本身作為裝箱容器。
Integer類的static屬性定義了大量和int有關的常量。
Integer類的static方法定義了和int有關的工具函數。
屬性和構造函數先來看屬性。
private final int value; public Integer(int value) { this.value = value; }
對的,Integer對象中,只有包含這么一個數據,被裝箱的原始值。
簡單到不能再簡單。
我們知道,一般來說,在java中,使用工廠方法代替構造函數是更好的設計。在Integer里,就體現了它的好處之一。
Integer提供了一組靜態工廠方法:
public static Integer valueOf(String s) throws NumberFormatException { return Integer.valueOf(parseInt(s, 10)); } public static Integer valueOf(String s, int radix) throws NumberFormatException { return Integer.valueOf(parseInt(s,radix)); } public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
前兩個工廠方法都利用最后一個工廠方法實現。最重要的是最后一個。
非常明顯,當被裝箱的原始類型i在IntegerCache.low和IntegerCache.high之間時,則返回緩存的Integer對象。
來看IntegerCache:
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() {} }
可發現:
默認緩存的值是-128到127。
緩存的范圍可以通過java.lang.Integer.IntegerCache.high來設置。這樣,如果在某些場景下Integer影響性能,可以通過jvm手動修改該參數空間換時間。
總結一下,由于Integer是對象,而對整數的操作是代碼里非常頻繁的地方。裝箱機制會導致程序產生大量的Integer對象,這導致:
對象會占據額外空間(如對象頭),造成內存浪費。
頻繁創建銷毀對象,給gc造成壓力。
因此,采用緩存機制,盡量降低裝箱對性能的影響。
其它裝箱類其它裝箱類的代碼這里就不分析了。重點關注下各裝箱類的緩存范圍。
首先,Boolean,只有兩個值,當然可以都緩存。
浮點類型,Double和Float,沒有緩存:
public static Float valueOf(float f) { return new Float(f); } public static Double valueOf(double d) { return new Double(d); }
Short,緩存范圍為-128到127,和默認的Integer一樣。最重要的是,這個范圍無法修改。
public static Short valueOf(short s) { final int offset = 128; int sAsInt = s; if (sAsInt >= -128 && sAsInt <= 127) { // must cache return ShortCache.cache[sAsInt + offset]; } return new Short(s); } private static class ShortCache { private ShortCache(){} static final Short cache[] = new Short[-(-128) + 127 + 1]; static { for(int i = 0; i < cache.length; i++) cache[i] = new Short((short)(i - 128)); } }
同樣:
Byte緩存范圍也是-128到127,全部緩存。
而Character緩存范圍為0到127.
Long的緩存范圍為-128到127。
可以發現,只有Integer的緩存范圍能夠修改,其它的裝箱類型都不行。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/77093.html
摘要:本章部分內容從源碼中解讀一些自動裝箱與拆箱的原理,以及會出現的一些陷阱已經性能等。例題分析我們通過幾個經典的問題,來看看大家到底理解了裝箱與拆箱的知識點沒。 showImg(https://img-blog.csdnimg.cn/20190426221838971.gif);showImg(https://img-blog.csdnimg.cn/20190426221918208.pn...
摘要:棧隊列雙端隊列都是非常經典的數據結構。結合了棧和隊列的特點。因此,在中,有棧的使用需求時,使用代替。迭代器之前源碼源碼之與字段中分析過,容器的實現中,所有修改過容器結構的操作都需要修改字段。 棧、隊列、雙端隊列都是非常經典的數據結構。和鏈表、數組不同,這三種數據結構的抽象層次更高。它只描述了數據結構有哪些行為,而并不關心數據結構內部用何種思路、方式去組織。本篇博文重點關注這三種數據結構...
摘要:哪吒社區技能樹打卡打卡貼函數式接口簡介領域優質創作者哪吒公眾號作者架構師奮斗者掃描主頁左側二維碼,加入群聊,一起學習一起進步歡迎點贊收藏留言前情提要無意間聽到領導們的談話,現在公司的現狀是碼農太多,但能獨立帶隊的人太少,簡而言之,不缺干 ? 哪吒社區Java技能樹打卡?【打卡貼 day2...
摘要:不相等的對象要具有不相等的哈希碼為了哈希表的操作效率,這一點很重要,但不是強制要求,最低要求是不相等的對象不能共用一個哈希碼。方法和方法協同工作,返回對象的哈希碼。這個哈希碼基于對象的身份生成,而不是對象的相等性。 本文面向 剛學完Java的新手們。這篇文章不講語法,而是一些除了語法必須了解的概念。 將要去面試的初級工程師們。查漏補缺,以免遭遇不測。 目前由于篇幅而被挪出本文的知識...
摘要:最近算是比較深入的了解了一下的源碼,就想著寫點東西記錄一下,一來可以加深理解,再來也算是為我刷了那么久平臺貢獻一點自己的綿薄之力。這兩個方法都是給當前的實例的屬性賦值,參數為類型的構造器直接將參數賦值給屬性,參數為是將方法的返回值賦值。 最近算是比較深入的了解了一下Integer的源碼,就想著寫點東西記錄一下,一來可以加深理解,再來也算是為我刷了那么久segmentfault平臺貢獻一...
閱讀 2812·2019-08-30 15:55
閱讀 2858·2019-08-30 15:53
閱讀 2296·2019-08-26 13:47
閱讀 2558·2019-08-26 13:43
閱讀 3157·2019-08-26 13:33
閱讀 2805·2019-08-26 11:53
閱讀 1798·2019-08-23 18:35
閱讀 801·2019-08-23 17:16