萬事從最基本的開始。
要想完全掌握 NIO,並不是掌握上面文章(【死磕NIO】— NIO基礎詳解)中的三大元件就可以了,我們還需要掌握一些基本概念,如什麼是 IO,5 種IO模型的區別,什麼是阻塞&非阻塞等等,只有掌握了這些基本概念,我們對NIO才能理解得更加得心應手。
這篇文章我們就從阻塞&非阻塞,同步&非同步說起。
同步與非同步
什麼是同步與非同步呢?百度百科是這樣定義的:
同步指兩個或兩個以上隨時間變化的量在變化過程中保持一定的相對關係。
非同步與同步相對(這解釋讓我無言相對)
所以,我們需要明確的是同步與非同步針對的是兩個或者兩個以上的事物
。
對於同步而言,一個任務(呼叫者)的完成需要依賴另一個人任務(被呼叫者)的完成,只有等待被依賴的任務完成,依賴的任務才會繼續進行,兩者步調保持一致。
非同步呢?任務與它依賴的任務沒有必然的聯絡,它不需要等待它依賴的任務完成,它只需要向依賴任務發起呼叫即可,告訴它你可以幹活了,至於你啥時候幹完跟我沒關係。
所以說,同步和非同步的本質區別就在於呼叫者與被呼叫者之間結果訊息通知機制的不同
。
- 同步:呼叫者需要一直
主動等待
被呼叫者的結果。 - 非同步:呼叫者呼叫被呼叫者後,呼叫者不會立刻得到結果,在呼叫者發起呼叫後,被呼叫者通過狀態、通知或通過回撥函式,讓呼叫者知道結果
所以,同步和非同步一個是主動等待結果,一個是被動知道結果。
舉一個簡單的例子:買奶茶,我們有兩種方式拿到我們買的奶茶
- 選擇排隊等待。這種方式就是同步等待訊息通知了,我們需要一直在吧檯面前等著我們的奶茶
- 掃碼。這種方式,你可以不停地看手機排號是否到你了(狀態),也可以在那裡玩手機等著服務員喊 88 號,奶茶好了(通知)。
上面提到非同步呼叫可以通過狀態、通知或者回撥函式來告知呼叫者。
- 狀態:呼叫者需要每隔一段向被呼叫者發起一個狀態查詢請求。這種方式效率較為低下。一般我們在呼叫支付介面的時候,如果服務方告知支付狀態未知,則我們需要每隔一段時間去查詢該筆訂單的支付狀態。雖然效率較為低下,但是靠譜。
- 通知:這種方式,呼叫者不需要做額外的工作,他只需要等被呼叫者把結果告訴呼叫者即可。但是這種方式也有點不是那麼靠譜,它到底啥時候呼叫,如果不呼叫怎麼辦呢?這些都是我們需要考慮的問題。
- 回撥函式:和通知機制差不多。
阻塞與非阻塞
上面解釋了什麼是同步與非同步,那什麼是阻塞與非阻塞呢?
所謂阻塞,就是有障礙而不能通行,無法暢通。
所以,阻塞就是呼叫結果返回之前,該執行緒會被一直掛起,一直等待結果,不能繼續,函式只有在得到結果之後才會返回
。
可能有小夥伴會將阻塞與同步等同起來,因為他們都是因為等待執行結果而停滯不前,其實兩者還是有區別的:
- 同步,針對的是兩個程式,一個程式(呼叫者)因為等待另一個程式(被呼叫者)的執行結果而停滯不前。而阻塞則是針對一個,它是因為自己本身因等待當前執行緒中某個執行結果而停滯不前的。
- 對於同步來說,當前執行緒還是處於啟用狀態,只是從邏輯(感官)來說它是停滯不前的,當前執行緒可能還在處理其他事情。而阻塞則不同,當前執行緒是被掛起了,直接讓出了 CPU。
非阻塞則與阻塞概念相對,指在不能立即得到執行結果之前,該函式不會阻礙當前執行緒執行,而是會立即返回
。
還是上面那個買奶茶的例子,不論是排隊在那裡等奶茶還是掃碼在哪裡等奶茶,只要在等奶茶的過程中你沒有做其他事情都是阻塞。如果你在等的過程跟你女朋友聊天(假如你有女朋友的話)或者在玩手機,那麼就是非阻塞,因為沒有因等待奶茶這件事一直耗著,而是一邊等一邊幹其他的事情。
同步&非同步、阻塞&非阻塞
同步&非同步與阻塞&非阻塞兩兩組合,分別為同步阻塞
,同步非阻塞
,非同步阻塞
,非同步非阻塞
。以上面等奶茶的例子為例。
同步阻塞
你在排隊等奶茶的過程中,什麼事情都不能做,只能乾等著。就問你無聊不無聊,尷尬不尷尬。效率最為低下
。
同步非阻塞
你在排隊等奶茶的過程中,可以幹其他事情,比如刷抖音,玩一把王者榮耀,但是你需要不斷地看奶茶是否已經到你,你勢必會分心導致輸掉王者榮耀,成為一個坑貨。注意排隊等奶茶,玩王者榮耀是兩件事情,你需要兩件事情來回不斷地切換,效率也不見得高到哪裡去
。
非同步阻塞
你掃碼拿號後,你不用在那裡排隊乾等,你只需要等候服務員告訴你奶茶做好了去拿就可以了,但是在這個等的過程中,你啥事都不能幹,只能乾等著。很顯然你已經被阻塞在這個等待服務員告訴你奶茶做好了的事情(訊息通知
)上面了。我們要注意是,並不是說非同步就不能阻塞了,非同步也是可以阻塞的,只不過它不是在處理訊息時阻塞,而是在等待訊息通知時被阻塞了
。
非同步非阻塞
你掃碼拿號後,直接去邊上玩王者榮耀了,中途你專心玩的王者榮耀,不需要分心去關注你的奶茶是否做好了,你只需要在那裡等服務員告訴你奶茶做好了(訊息通知
)去拿就可以了。效率最高
。