將阻塞方法轉換為非同步
根據你的連線,以下方法將花費一秒或兩秒來檢索網頁並計算文字長度。無論什麼執行緒呼叫它都會阻塞那段時間。它也會重新丟擲一個稍後有用的異常。
public static long blockingGetWebPageLength(String urlString) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(new URL(urlString).openConnection().getInputStream()))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
return sb.toString().length();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
這將它轉換為一個方法,通過將阻塞方法呼叫移動到另一個執行緒立即返回。預設情況下,supplyAsync 方法將在公共池上執行供應商。對於阻塞方法,這可能不是一個好選擇,因為可能會耗盡該池中的執行緒,這就是我新增可選服務引數的原因。
static private ExecutorService service = Executors.newCachedThreadPool();
static public CompletableFuture<Long> asyncGetWebPageLength(String url) {
return CompletableFuture.supplyAsync(() -> blockingGetWebPageLength(url), service);
}
要以非同步方式使用該函式,應該使用接受 lamda 的方法,當它完成時接受供應商的結果,例如 thenAccept。此外,使用 exceptionly 或 handle 方法記錄可能發生的任何異常也很重要。
public static void main(String[] args) {
asyncGetWebPageLength("https://stackoverflow.com/")
.thenAccept(l -> {
System.out.println("Stack Overflow returned " + l);
})
.exceptionally((Throwable throwable) -> {
Logger.getLogger("myclass").log(Level.SEVERE, "", throwable);
return null;
});
}