您現在的位置是:首頁 > 動作武俠首頁動作武俠

Java常用類庫與技巧

簡介ArithmeticException:by zeroFinally執行後的值為:2執行結束注意儘量細化異常,別丟擲異常的父類,也是為了方便定位問題避免在finally中寫return語句,其他return不會執行Java異常的處理原

異常類由什麼組成

Java異常

異常處理機制主要回答了三個問題

What:異常型別回答了什麼被丟擲

Where:異常堆疊跟蹤回答了在哪丟擲

Why:異常資訊回答了為什麼被丟擲

Java的異常體系

Java常用類庫與技巧

Java常用類庫與技巧

Error和Exception的區別

從概念角度解析Java的異常處理機制:

1。Error:程式無法處理的系統處理,編輯器不做檢查(如系統崩潰,虛擬機器錯誤,記憶體空間不足,方法呼叫棧溢位等)

2。Exception:程式可以處理的異常,捕獲後可能恢復

RuntimeException:不可預知的,程式應當自行避免

非RuntimeException:可預知的,從編譯器校驗的異常

從責任角度看:

1。Error屬於JVM需要負擔的責任

2。RuntimeException是程式應該負擔的責任

3。Checked Exception可檢查異常是Java編譯器應該負擔的責任(編譯時就應該捕獲或者丟擲的異常)

常見Error以及Exception

RuntimeException

1。NullPointerException - 空指標引用異常

2。ClassCastException - 型別強制轉換異常

3。IllegalArgumentException - 傳遞非法引數異常

4。IndexOutOfBoundsException - 下標越界異常

5。NumberFormatException - 數字格式異常

非RuntimeException

1。ClassNotFoundException - 找不到指定class的異常

2。IOException - IO操作異常

3。SQLException - SQL異常

Error

1。NoClassDefFoundError - 找不到class定義的異常(原因:類依賴的class或者jar不存在;類檔案存在,但是存在不同的域中;大小寫問題,javac編譯的時候是無視大小寫的,很有可能編譯出來的class檔案就與想要的不一樣)

2。StackOverflowError - 深遞迴導致棧被耗盡而丟擲的異常

3。OutOfMemoryError - 記憶體溢位異常

Java的異常處理機制

丟擲異常:建立異常物件,交由執行時系統處理

捕獲異常:尋找合適的異常處理器處理異常,否則終止執行

private static int doSomething(){ try { int i = 10/0; System。out。println(“i= ” + i); } catch (ArithmeticException e) { System。out。println(“ArithmeticException: ” + e); return 0; } catch (Exception e) { System。out。println(“Exception: ” + e); return 1; } finally { System。out。println(“Finally”); return 2; }}public static void main(String[] args) { System。out。println(“執行後的值為:” + doSomething()); System。out。println(“執行結束”);}

Java常用類庫與技巧

執行結果

ArithmeticException: java。lang。ArithmeticException: / by zeroFinally執行後的值為:2執行結束

Java常用類庫與技巧

注意

儘量細化異常,別丟擲異常的父類,也是為了方便定位問題

避免在finally中寫return語句,其他return不會執行

Java異常的處理原則

具體明確:丟擲的異常應能透過異常類名和message準確說明異常的型別和產生異常的原因

提早丟擲:應儘可能早的發現並丟擲異常,便於精確定位問題

延遲捕獲:異常的捕獲和處理應儘可能延遲,讓掌握更多資訊的作用域來處理異常

高效主流的異常處理框架

在使用者看來,應用系統發生的所有異常都是應用系統內部的異常

設計一個通用的繼承自RuntimeException的異常來統一處理

其餘異常都統一轉譯為上述異常AppException

在catch之後,丟擲上述異常的子類,並提供足以定位的資訊

由前端接收AppException做統一處理

看看try-catch的效能問題

private static void testException(String[] array){ try { System。out。println(array[0]); }catch (NullPointerException e){ System。out。println(“array cannot be null”); }}private static void testIf(String[] array){ if (array != null){ System。out。println(array[0]); } else { System。out。println(“array cannot be null”); }}public static void main(String[] args) { long start = System。nanoTime(); testException(null); System。out。println(“testException cost ” + (System。nanoTime() - start));}// 執行結果 array cannot be nulltestException cost 322997public static void main(String[] args) { long start = System。nanoTime(); testIf(null); System。out。println(“testIf cost ” + (System。nanoTime() - start));}// 執行結果 array cannot be nulltestIf cost 238152

Java常用類庫與技巧

Java異常處理消耗效能的地方

try-catch塊影響JVM的最佳化

異常物件例項需要保持棧快照等資訊,開銷較大

Java集合框架

集合之List和Set

Java常用類庫與技巧

Java常用類庫與技巧

集合之Map

Java常用類庫與技巧

Java常用類庫與技巧

HashMap、HashTable、ConcurrentHashMap

HashMap

Java8以前(不包含):陣列+連結串列

Java常用類庫與技巧

Java常用類庫與技巧

陣列長度預設是16,陣列中每個元素儲存著連結串列的頭節點,透過hash(key。hashCode())%len(雜湊函式取模操作)獲得新增元素所要存放的陣列的位置。

有個問題,如果雜湊函式計算的值一直是同一個,會導致bucket(桶)過長,連結串列查詢,就需要從頭部開始遍歷,最壞的情況下,效能會從O(1)變成O(n)。

Java8以後:陣列+連結串列+紅黑樹

Java8之後做了調整,會透過一個常量TREEIFY_THRESHOLD控制是否將連結轉成紅黑樹,效能從O(n)提高到O(logn)

Java常用類庫與技巧

Java常用類庫與技巧

HashMap使用懶載入,首次使用才初始化

HashMap:put方法的邏輯

1、如果HashMap未被初始化過,則初始化

2、對Key求Hash值,然後計算下標

3、如果沒有碰撞,直接放入桶中

4、如果碰撞了,以連結串列的方式連結到後面

5、如果連結串列長度超過閾值,就把連結串列轉成紅黑樹

6、如果連結串列長度低於6,就把紅黑樹轉回連結串列

7、如果節點已經存在就替換舊值

8、如果桶滿了(容量16*載入因子0。75),就需要resize(擴容2倍後重排)

HashMap:如何有效減少碰撞

擾動函式:促使元素位置分佈均勻,減少碰撞機率(兩個不相等的物件返回不同的雜湊值)

使用final物件,並採用合適的equals()和hashCode()方法

HashMap:從獲取hash到雜湊的過程

Java常用類庫與技巧

Java常用類庫與技巧

HashMap:擴容問題

多執行緒環境下,調整大小會存在條件競爭,容易造成死鎖

rehashing是一個比較耗時的過程

Hashtable

注意點

多執行緒安全,鎖住整個HashTable,力度大

底層:陣列+連結串列

無論key還是value都不能為null

如何最佳化Hashtable

透過鎖細粒度化,將整鎖拆解成多個鎖進行最佳化,所以出現了ConcurrentHashMap

ConcurrentHashMap

早期的ConcurrentHashMap:透過分段鎖Segment來實現

陣列+連結串列

Java常用類庫與技巧

Java常用類庫與技巧

當前的ConcurrentHashMap:CAS+synchronized使鎖更細化

陣列+連結串列+紅黑樹

Java常用類庫與技巧

Java常用類庫與技巧

ConcurrentHashMap:put方法的邏輯

1。判斷Node[]陣列是否初始化,沒有則進行初始化操作

2。透過hash定位陣列的索引座標,是否有Node節點,如果沒有則使用CAS進行新增(連結串列的頭節點),新增失敗則進入下次迴圈

3。檢查到內部正在擴容,就幫助它一塊擴容。

4。如果f!=null,則使用synchronized鎖住f元素(連結串列/紅黑二叉樹的頭元素)

4。1如果是Node(連結串列結構)則執行連結串列的新增操作

4。2如果是TreeNode(樹型結構)則執行樹新增操作

5。判斷連結串列長度已經達到臨界值8(預設值),當節點數超過這個值就需要把連結串列轉換為樹結構

ConcurrentHashMap總結

比起Segment,鎖拆得更細

首先使用無鎖操作CAS插入頭節點,失敗則迴圈重試

若頭節點已存在,則嘗試獲取頭節點的同步鎖,再進行操作

HashMap、Hashtable、ConcurrentHashMap區別

HashMap執行緒不安全,陣列+連結串列+紅黑樹

Hashtable執行緒安全,鎖住整個物件,陣列+連結串列

ConcurrentHashMap執行緒安全,CAS+同步鎖,陣列+連結串列+紅黑樹

HashMap的key、value均可為null,而其他的兩個類不支援

J。U。C知識點梳理

java。util。concurrent:提供了併發程式設計的解決方案

CAS是java。util。concurrent。atomic包的基礎

AQS是java。util。concurrent。locks包以及一些常用類比如Semophore,ReentrantLock等類的基礎

J。U。C包的分類

執行緒執行器executor

鎖locks

原子變數類atomic

併發工具類tools

併發集合collections

併發工具類

閉鎖CountDownLatch

柵欄CyclicBarrier

訊號量Semaphore

交換器Exchanger

CountDownLatch

讓主執行緒等待一組事件發生後繼續執行,事件指的是CountDownLatch裡的countDown()方法

Java常用類庫與技巧

Java常用類庫與技巧

Java常用類庫與技巧

Java常用類庫與技巧

CyclicBarrier

阻塞當前執行緒,等待其他執行緒

等待其它執行緒,且會阻塞自己當前執行緒,所有執行緒必須同時到達柵欄位置後,才能繼續執行

所有執行緒到達柵欄處,可以觸發執行另外一個預先設定的執行緒

Java常用類庫與技巧

Java常用類庫與技巧

Semaphore

控制某個資源可被同時訪問的執行緒個數

Java常用類庫與技巧

Java常用類庫與技巧

Java常用類庫與技巧

Java常用類庫與技巧

Exchanger

主要用於執行緒間的資料交換,它提供一個同步點,一個執行緒到達同步點就會被阻塞,直到另外一個執行緒進入到同步點為止,兩個執行緒到達同步點後,相互交換資料。

Java常用類庫與技巧

Java常用類庫與技巧

Java常用類庫與技巧

Java常用類庫與技巧

BlockingQueue

提供可阻塞的入隊和出隊操作,如果佇列滿了,入隊操作將阻塞,直到有空間可用,如果佇列空了,出隊操作將阻塞,直到有元素可用。

Java常用類庫與技巧

Java常用類庫與技巧

主要用於生產者-消費者模式,在多執行緒場景時生產者執行緒在佇列尾部新增元素,而消費者執行緒則在佇列頭部消費元素,透過這種方式能夠達到將任務的生產和消費進行隔離的目的

主要有以下七個佇列實現,都是執行緒安全的

1、ArrayBlockingQueue:一個由陣列結構組成的有界阻塞佇列(有界指的是容量大小有限制,先進先出)

2、LinkedBlockingQueue:一個由連結串列結構組成的有界/無界阻塞佇列(先進先出)

3、PriorityBlockingQueue:一個支援優先順序排序的無界阻塞佇列

4、DealyQueue:一個使用優先順序佇列實現的無界阻塞佇列

5、SynchronousQueue:一個不儲存元素的阻塞佇列

6、LinkedTransferQueue:一個由連結串列結構組成的無界阻塞佇列

7、LinkedBlockingDeque:一個由連結串列結構組成的雙向阻塞佇列

Java的IO機制

BIO

Block-IO:其實是傳統的java。net,java。io包下的介面或者類,比如java。net下的socket,servletSocket和http,因為網路通訊都是IO行為,所以可以說是BIO的範疇,傳統的IO基於位元組流和字元流進行操作,比如InputStream和OutputStream,Reader和Writer。

BIO是基於流模型實現的,這意味著其互動方式是同步阻塞的,在讀取輸入流或者寫入輸出流時,在讀寫操作完成之前,執行緒會一直阻塞,它們之間的呼叫是可靠的線性順序,程式傳送請求給核心,然後由核心進行通訊,在核心準備好資料之前,執行緒是被掛起的,所以在兩個階段,程式都處於掛起狀態,類比成ClientServlet模式,其實現模式為一個連線一個執行緒,即客戶端有連線請求時,則服務端啟動一個執行緒處理,待作業系統返回結果,如果這個連線不做任何事情,會造成不必要的執行緒開銷,當然,我們可以透過執行緒池機制來改善。

特點:在IO執行的階段,都被阻塞住了

好處:程式碼比較簡單

缺點:IO擴充套件性和效率存在瓶頸

Java常用類庫與技巧

Java常用類庫與技巧

NIO(Java4)

NonBlock-IO:構建多路複用的、同步非阻塞的IO操作,提供了更接近作業系統底層的高效能資料操作方式

特點:程式要不斷去詢問核心是否準備好

Java常用類庫與技巧

Java常用類庫與技巧

NIO核心

Channels

Buffers

Selectors

AIO

Asynchronous IO:基於事件和回撥機制

Java常用類庫與技巧

Java常用類庫與技巧

AIO如何進一步加工處理結果

基於回撥:實現CompletionHandler介面,呼叫時觸發回撥函式

返回Future:透過isDone()檢視是否準備好,透過get()等待返回資料

區別

Java常用類庫與技巧

Java常用類庫與技巧

AIO連server都免了,所以是0:N

BIO適用於連線數少且固定的架構,這種方式對伺服器的資源要求較高,1。4之前的唯一選擇

NIO適用於連線數多且短的架構,比如聊天伺服器,程式設計複製

AIO適用於連線數多且長的架構,比如相簿伺服器,可以充分呼叫OS來參與併發操作,程式設計複製,1。7才出現的

Top