將阻塞方法轉換為非同步

根據你的連線,以下方法將花費一秒或兩秒來檢索網頁並計算文字長度。無論什麼執行緒呼叫它都會阻塞那段時間。它也會重新丟擲一個稍後有用的異常。

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;
            });

}