編程中一直對這兩個概念不是很理解,在網上搜了很多資料大概描述的其實都很模糊,有時候還自相矛盾,很容易搞混,這里說一下我對這兩個概念的理解,
首先看一下相關技術書籍對這兩個概念的描述,下面分別是摘自《深入理解Java核心技術》和《Java并發程式設計中的》的內容,
摘自《深入理解Java核心技術》14.2:
當I/O操作發生時,一定是有兩方參與的,分別是呼叫方和被呼叫方,阻塞和非阻塞描述的是呼叫方,同步和異步描述的是被呼叫方,
例如A呼叫B:
1.如果是阻塞,那么A在發出呼叫命令后,要一直等待B回傳結果,
2.如果是非阻塞,那么A在發出呼叫命令后,不需要等待,可以去做自己的事情,
3.如果是同步,那么B在收到A的呼叫命令后,會立即執行要做的事,A的本次呼叫可以得到結果
4.如果是異步,那么B在收到A的呼叫命令后,不保證會立即執行要做的事,但是保證會做,B在做好了之后會通知A,A的本次呼叫得不到·結果,但是B執行完成要做的事之后會通知A,
因為同步/異步與阻塞/非阻塞描述的物件不同,所以這二者之間是沒有必然聯系的,也就是說,同步不一定阻塞,異步也不一定非阻塞,
只不過通常很少存在異步且阻塞的場景,所以很多人誤以為同步一定是非阻塞的、異步一點事非阻塞的,
摘自《Java高并發程式設計》1.2:
同步和異步通常用來形容一次方法的呼叫,同步方法呼叫一旦開始,呼叫者必須等到方法呼叫回傳后,才能繼續后續的行為,異步方法呼叫更像一個訊息傳遞,一旦開始,方法呼叫就會立即回傳,呼叫者就可以繼續后續的操作,而異步方法通常會在另外一個執行緒中“真實”地執行,整個程序,不會阻礙呼叫者的作業,對于呼叫者來說,異步呼叫似乎是一瞬間就完成的,如果異步呼叫需要回傳結果,那么當這個異步呼叫真實完成時,則會通知呼叫者,
阻塞和非阻塞通常用來形容多執行緒間的相互影響,比如一個執行緒占用了臨界區資源,那么其他所有需要這個資源的執行緒就必須在這個臨界區中進行等待,等待會導致執行緒掛起,這種情況就是阻塞,此時,如果占用資源的執行緒一直不愿意釋放資源,那么其他所有阻塞在這個臨界區上的執行緒都不能作業, 非阻塞的意思與之相反,它強調沒有一個執行緒可以妨礙其他執行緒執行,所有的執行緒都會嘗試不斷前向執行,
兩本書籍的描述切入點不一樣,乍一看兩個書籍描述的可能還有點沖突,反而讓人更迷糊,
在我看來阻塞和非阻塞必然是執行緒或行程相關的,阻塞指的是如果執行緒無法立即完成任務是否會進入阻塞狀態,非阻塞則與之相反,
同步即所有的代碼都是按順序執行的,可以理解為這個事情不干完了我就不干別的事情,異步則不可預測順序的,異步呼叫必須伴隨著通知,可以理解為等到取值完成后我再進行后續的操作,我先去干別的事情,
同步異步和阻塞非阻塞搭配就會出現如下四種組合:
- 同步阻塞,如果不能立即獲取資料,則執行緒阻塞等待資料回傳,因為程式阻塞了,需要有其他程式將程式喚醒(這里很重要),如java類FileInputStream的readBytes操作,
- 同步非阻塞,如果不能立即獲取資料,則回圈檢查資料是否完成,這里不需要其他執行緒參與喚醒操作,比如java類AtomicInteger的自增操作,如果不能加1就回圈執行,
- 異步非阻塞,如果不能立即獲取資料,則立即回傳執行其他操作,等到資料回傳了,接收到通知后再進行后續的處理作業(這里后續的處理操作是別的執行緒去做了,因為當前執行緒可能已經退出了),
- 異步阻塞,這應該是一個并不存在的組合,異步和阻塞是互斥的,既然都可以異步執行,你還阻塞干什么呢,執行完成之后再通知你不就好了嗎,異步的目的不就是無法立即獲取資料讓執行緒去干別的事情嗎,如果沒有別的事情可做就同步阻塞等待就可以了,
總結:
如果一個程式說他是異步的,那他肯定非阻塞的,因為并不存在異步阻塞,開啟異步的目的就是不想讓當前執行緒阻塞,讓他去干其他事情,就是你需要獲取一個資源或發出一個通知,但是你并不能立即獲取這個資源或者知道通知是否發送成功,這個時候你就需要執行緒去干別的事(這里的別的事指不依賴前面呼叫回傳結果的代碼),等結果出來了再對結果進行處理,如對資源決議或者重新發送訊息,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/498408.html
標籤:Java
下一篇:記憶體分析器 (MAT)
