同步與異步
同步與異步
的概念, 關注的是 消息通信機制
-
是指發出一個請求, 在沒有得到結果之前該請求就不傳回結果, 請求傳回時, 也就得到結果了.同步
比如洗衣服, 把衣服放在洗衣機裡, 沒有洗好之前我們一直看着, 直到洗好了才拿出來晾曬.
-
是指發出一個請求後, 立刻得到了回應, 但沒有傳回結果. 這時我們可以再處理别的事情(發送其他請求), 是以這種方式需要我們通過狀态主動檢視是否有了結果, 或者可以設定一個回調來通知調用者.異步
比如洗衣服時, 把衣服放到洗衣機裡, 我們就可以去做别的事情, 過會兒來看看有沒有洗好(通過狀态查詢);
或者我們設定洗衣機洗完後響鈴來通知我們洗好了(回調通知)
阻塞與非阻塞
阻塞與非阻塞
很容易和
同步與異步
混淆, 但兩者關注點是不一樣的.
阻塞與非阻塞
關注的是 程式在等待調用結果時的狀态
-
是指請求結果傳回之前, 目前線程會被挂起(被阻塞), 這時線程什麼也做不了阻塞
-
是指請求結果傳回之前, 目前線程沒有被阻塞, 仍然可以做其他事情.非阻塞
阻塞
有個明顯的特征就是線程通常是處于
BLOCKED
狀态(BIO中的
read()
操作時, 線程阻塞是JVM配合OS完成的, 此時Java擷取到線程的狀态仍是
RUNNABLE
但它确實已經被阻塞了)
如果要拿
同步
來做比較的話, 同步通信方式中的線程在發送請求之後等待結果這個過程中應該處于
RUNNABLE
狀态, 同步必須一步一步來完成, 就像是代碼必須執行完一行才能執行下一行, 是以必須等待這個請求傳回之後才可進行下一個請求, 即使等待結果的時間長, 也是在執行這個請求的過程中. 而
異步
則不用等上一條執行完, 可以先執行别的代碼, 等請求有了結果再來擷取結果.
IO模型
Java中的IO操作是JVM配合作業系統來完成的. 對于一個IO的讀操作, 資料會先被拷貝到作業系統核心的緩沖區中, 然後從作業系統核心的緩沖區拷貝到應用程式的位址空間. 是以整個過程可分為兩個階段:
- 等待I/O資料準備好. 這取決于IO目标傳回資料的速度, 如網絡IO時看網速和資料本身的大小.
- 資料從核心緩沖區拷貝到程序内.
根據這兩個階段, 産生了常見的幾種不同的IO模型:
BIO
,
NIO
IO多路複用
和
AIO
.
BIO
BIO
即
Blocking I/O
(阻塞 I/O), BIO整個過程如下圖:

程式發送請求給核心, 然後由核心去進行通信, 在核心準備好資料之前這個線程是被挂起的, 是以在兩個階段程式都處于挂起狀态.
- BIO的特點就是在IO執行的兩個階段都被block了
NIO
NIO
Non-Blocking I/O
(非阻塞 I/O), NIO整個過程如下圖:
與BIO的明顯差別是, 發起第一次請求後, 線程并沒有被阻塞, 它反複檢查資料是否準備好, 把原來大塊不能用的阻塞時間分成了許多”小阻塞”(檢查), 是以程序不斷有機會被執行. 這個檢查有沒有準備好資料的過程有點類似于”輪詢”.
- NIO的特點就是程式需要不斷的主動詢問核心資料是否準備好。第一個階段非阻塞, 第二個階段阻塞
IO多路複用
IO多路複用(
I/O Multiplexing
)有
select
poll
epoll
等不同方式, 它的優點在于單個線程可以同時處理多個網絡IO.
NIO
中輪詢操作是使用者線程進行的, 如果把這個任務交給其他線程, 則使用者線程就不用這麼費勁的查詢狀态了.
IO多路複用
調用系統級别的
select
或
poll
模型, 由系統進行監控IO狀态. select輪詢可以監控許多socket的IO請求, 當有一個socket的資料準備好時就可以傳回.
- select: 注冊事件由數組管理, 數組是有長度的, 32位機上限1024, 64位機上限2048. 輪詢查找時需要周遊數組.
- poll: 把select的數組采用連結清單實作, 是以沒了最大數量的限制
- epoll方式: 基于事件回調機制, 回調時直接通知程序, 無須使用某種方式來檢視狀态.
多路複用IO過程圖:
使用者線程有一段時間是阻塞的, 從上圖來看, 與
NIO
很像, 但與NIO不一樣的是, select不是等到所有資料準備好才傳回, 而是隻要有一個準備好就傳回, 它的優勢在于可以同時處理多個連接配接. 若連接配接不是很多的話, 它的效率不一定高, 可能還會更差.
Java 1.4
開始支援
NIO(New IO)
, 就是采用了這種方式, 在套接字上提供
selector
選擇機制, 當發起
select()
時會阻塞等待至少一個事件傳回.
- 多路複用IO的特點是使用者程序能同時等待多個IO請求, 系統來監控IO狀态, 其中的任意一個進入讀就緒狀态, select函數就可以傳回.
AIO
AIO
Asynchronous I/O
(異步 I/O), 這是
Java 1.7
引入的
NIO 2.0
中用到的. 整個過程中, 使用者線程發起一個系統調用之後無須等待, 可以處理别的事情. 由作業系統等待接收内容, 接收後把資料拷貝到使用者程序中, 最後通知使用者程式已經可以使用資料了, 兩個階段都是非阻塞的. AIO整個過程如下圖:
AIO
屬于異步模型, 使用者線程可以同時處理别的事情, 我們怎麼進一步加工處理結果呢? Java在這個模型中提供了兩種方法:
- 一種是基于”回調”, 我們可以實作
接口, 在調用時把回調函數傳遞給對應的API即可CompletionHandler
- 另一種是傳回一個
. 處理完别的事情, 可以通過Future
可檢視是否已經準備好資料, 通過isDone()
方法等待傳回資料.get()
小結
上面這幾種模式,
BIO
整個過程都等待傳回,
NIO
IO多路複用
在第二個階段等待傳回, 是以從整個過程來看, 這三個模式都屬于同步方式.
AIO
在整個過程中沒有等待傳回, 屬于異步方式.
熬夜不易,點選請老王喝杯烈酒!!!!!!!