這幾個概念困擾了我好久压储,現(xiàn)在此做下總結(jié):
阻塞:阻塞通常是指在一個執(zhí)行過程中暫停鲜漩,以等待某個條件的觸發(fā)。(包括IO 阻塞集惋、線程阻塞)
同步/異步:表示的發(fā)出調(diào)用后孕似,被調(diào)用者是否立即返回。
阻塞/非阻塞:表示調(diào)用方線程是否在等待數(shù)據(jù)就緒(例如:Socket通道數(shù)據(jù)是否已讀入內(nèi)存)
以下圖為例解釋一下:其中讀取數(shù)據(jù)分為2個步驟刮刑,1. 內(nèi)核等待數(shù)據(jù)可讀喉祭,2. 將內(nèi)核讀到的數(shù)據(jù)拷貝到進(jìn)程,其中第一個步驟為阻塞的(因為他在等待數(shù)據(jù)就緒)雷绢,而第二個步驟為非阻塞的沽讹。
描述的是從網(wǎng)卡讀取UDP數(shù)據(jù)包的過程
這張圖在第一個步驟中拜银,應(yīng)用進(jìn)程不斷的詢問內(nèi)核,當(dāng)數(shù)據(jù)沒有就緒時,內(nèi)核會立即返回焰檩,此時調(diào)用放線程也并未阻塞著等待數(shù)據(jù)就緒回右,可以做其他事情专控,所以第一個步驟為“異步非阻塞”的沾歪。
而第二個步驟,應(yīng)用進(jìn)程開始系統(tǒng)調(diào)用copy數(shù)據(jù)到用戶空間鸯匹,此時這個調(diào)用沒有立即返回坊饶,再結(jié)合上面的分析,所以這個步驟為“同步非阻塞的”殴蓬。
在Java中實現(xiàn)同步阻塞調(diào)用匿级、異步阻塞調(diào)用、異步非阻塞調(diào)用:
同步阻塞調(diào)用:
public class Test {
public static void main(String[] args) throws InterruptedException {
/* 同步阻塞調(diào)用:
調(diào)用沒有立即返回 => 同步
等待了數(shù)據(jù)就緒 => 阻塞
*/
int result = func();
func2(result);
}
public static int func() throws InterruptedException {
// 模擬(IO)阻塞
Thread.sleep(1000L);
// 模擬計算操作
return 1 + 1;
}
private static void func2(Integer result) {
// do something...
}
}
image
同步非阻塞演示不了
異步阻塞調(diào)用(此處使用join也能表現(xiàn)出來):
public class Test {
public static void main(String[] args) throws Exception {
/* 異步阻塞調(diào)用:
調(diào)用后立即返回 => 異步
返回后main線程直接獲取結(jié)果染厅,等待了數(shù)據(jù)就緒 => 阻塞
*/
FutureTask<Integer> futureTask = new FutureTask<>(Test::func);
new Thread(futureTask).run();
Integer result = futureTask.get();
func2(result);
}
private static int func() throws InterruptedException {
// 模擬(IO)阻塞
Thread.sleep(1000L);
// 模擬計算操作
return 1 + 1;
}
private static void func2(Integer result) {
// do something...
}
}
image
異步非阻塞調(diào)用:
public class Test {
public static void main(String[] args) throws Exception {
/* 異步非阻塞調(diào)用:
調(diào)用后立即返回 => 異步
調(diào)用后main線程直接就不管了痘绎,交由t1線程執(zhí)行后續(xù)的操作,main線程也沒有等待數(shù)據(jù)就緒 => 非阻塞
*/
CompletableFuture.supplyAsync(() -> func())
.thenAccept(result -> func2(result));
}
private static int func() {
// 模擬(IO)阻塞
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 模擬計算操作
return 1 + 1;
}
private static void func2(Integer result) {
// do something...
}
}
image