将阻塞方法转换为异步
根据你的连接,以下方法将花费一秒或两秒来检索网页并计算文本长度。无论什么线程调用它都会阻塞那段时间。它也会重新抛出一个稍后有用的异常。
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;
});
}