天天看點

【死磕NIO】— 阻塞、非阻塞、同步、異步,傻傻分不清楚

萬事從最基本的開始。

要想完全掌握 NIO,并不是掌握上面文章(【死磕NIO】— NIO基礎詳解)中的三大元件就可以了,我們還需要掌握一些基本概念,如什麼是 IO,5 種IO模型的差別,什麼是阻塞&非阻塞等等,隻有掌握了這些基本概念,我們對NIO才能了解得更加得心應手。

這篇文章我們就從阻塞&非阻塞,同步&異步說起。

什麼是同步與異步呢?百度百科是這樣定義的:

同步指兩個或兩個以上随時間變化的量在變化過程中保持一定的相對關系。 異步與同步相對(這解釋讓我無言相對)

是以,我們需要明确的是<code>同步與異步針對的是兩個或者兩個以上的事物</code>。

對于同步而言,一個任務(調用者)的完成需要依賴另一個人任務(被調用者)的完成,隻有等待被依賴的任務完成,依賴的任務才會繼續進行,兩者步調保持一緻。

異步呢?任務與它依賴的任務沒有必然的聯系,它不需要等待它依賴的任務完成,它隻需要向依賴任務發起調用即可,告訴它你可以幹活了,至于你啥時候幹完跟我沒關系。

是以說,<code>同步和異步的本質差別就在于調用者與被調用者之間結果消息通知機制的不同</code>。

同步:調用者需要一直<code>主動等待</code>被調用者的結果。

異步:調用者調用被調用者後,調用者不會立刻得到結果,在調用者發起調用後,被調用者通過狀态、通知或通過回調函數,讓調用者知道結果

是以,同步和異步一個是主動等待結果,一個是被動知道結果。

舉一個簡單的例子:買奶茶,我們有兩種方式拿到我們買的奶茶

選擇排隊等待。這種方式就是同步等待消息通知了,我們需要一直在吧台面前等着我們的奶茶

掃碼。這種方式,你可以不停地看手機排号是否到你了(狀态),也可以在那裡玩手機等着服務員喊 88 号,奶茶好了(通知)。

上面提到異步調用可以通過狀态、通知或者回調函數來告知調用者。

狀态:調用者需要每隔一段向被調用者發起一個狀态查詢請求。這種方式效率較為低下。一般我們在調用支付接口的時候,如果服務方告知支付狀态未知,則我們需要每隔一段時間去查詢該筆訂單的支付狀态。雖然效率較為低下,但是靠譜。

通知:這種方式,調用者不需要做額外的工作,他隻需要等被調用者把結果告訴調用者即可。但是這種方式也有點不是那麼靠譜,它到底啥時候調用,如果不調用怎麼辦呢?這些都是我們需要考慮的問題。

回調函數:和通知機制差不多。

上面解釋了什麼是同步與異步,那什麼是阻塞與非阻塞呢?

所謂阻塞,就是有障礙而不能通行,無法暢通。

是以,<code>阻塞就是調用結果傳回之前,該線程會被一直挂起,一直等待結果,不能繼續,函數隻有在得到結果之後才會傳回</code>。

可能有小夥伴會将阻塞與同步等同起來,因為他們都是因為等待執行結果而停滞不前,其實兩者還是有差別的:

同步,針對的是兩個程序,一個程序(調用者)因為等待另一個程序(被調用者)的執行結果而停滞不前。而阻塞則是針對一個,它是因為自己本身因等待目前線程中某個執行結果而停滞不前的。

對于同步來說,目前線程還是處于激活狀态,隻是從邏輯(感官)來說它是停滞不前的,目前線程可能還在處理其他事情。而阻塞則不同,目前線程是被挂起了,直接讓出了 CPU。

非阻塞則與阻塞概念相對,<code>指在不能立即得到執行結果之前,該函數不會阻礙目前線程執行,而是會立即傳回</code>。

還是上面那個買奶茶的例子,不論是排隊在那裡等奶茶還是掃碼在哪裡等奶茶,隻要在等奶茶的過程中你沒有做其他事情都是阻塞。如果你在等的過程跟你女朋友聊天(假如你有女朋友的話)或者在玩手機,那麼就是非阻塞,因為沒有因等待奶茶這件事一直耗着,而是一邊等一邊幹其他的事情。

同步&amp;異步與阻塞&amp;非阻塞兩兩組合,分别為<code>同步阻塞</code>,<code>同步非阻塞</code>,<code>異步阻塞</code>,<code>異步非阻塞</code>。以上面等奶茶的例子為例。

同步阻塞

你在排隊等奶茶的過程中,什麼事情都不能做,隻能幹等着。就問你無聊不無聊,尴尬不尴尬。<code>效率最為低下</code>。

同步非阻塞

你在排隊等奶茶的過程中,可以幹其他事情,比如刷抖音,玩一把王者榮耀,但是你需要不斷地看奶茶是否已經到你,你勢必會分心導緻輸掉王者榮耀,成為一個坑貨。注意排隊等奶茶,玩王者榮耀是兩件事情,你需要兩件事情來回不斷地切換,<code>效率也不見得高到哪裡去</code>。

異步阻塞

你掃碼拿号後,你不用在那裡排隊幹等,你隻需要等候服務員告訴你奶茶做好了去拿就可以了,但是在這個等的過程中,你啥事都不能幹,隻能幹等着。很顯然你已經被阻塞在這個等待服務員告訴你奶茶做好了的事情(<code>消息通知</code>)上面了。我們要注意是,并不是說異步就不能阻塞了,<code>異步也是可以阻塞的,隻不過它不是在處理消息時阻塞,而是在等待消息通知時被阻塞了</code>。

異步非阻塞

你掃碼拿号後,直接去邊上玩王者榮耀了,中途你專心玩的王者榮耀,不需要分心去關注你的奶茶是否做好了,你隻需要在那裡等服務員告訴你奶茶做好了(<code>消息通知</code>)去拿就可以了。<code>效率最高</code>。

https://www.cnblogs.com/xiaoQLu/p/10670333.html

https://zhuanlan.zhihu.com/p/385202919

PS:如果你覺得文章對你有所幫助,别忘了推薦或者分享,因為有你的支援,才是我續寫下篇的動力和源泉!

作者:chenssy。一個專注于【死磕 Java】系列創作的男人

出處:https://www.cnblogs.com/chenssy/p/15318107.html

作者個人網站:https://www.cmsblogs.com/。專注于 Java 優質系列文章分享,提供一站式 Java 學習資料

目前死磕系列包括:

    1. 【死磕 Java 并發】:https://www.cmsblogs.com/category/1391296887813967872(已完成)

    2.【死磕 Spring 之 IOC】:https://www.cmsblogs.com/category/1391374860344758272(已完成)

    3.【死磕 Redis】:https://www.cmsblogs.com/category/1391389927996002304(已完成)

    4.【死磕 Java 基礎】:https://www.cmsblogs.com/category/1411518540095295488

    5.【死磕 NIO】:https://www.cmsblogs.com/article/1435620402348036096

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。

繼續閱讀