Tôi có mã sau (kết quả từ my previous question) lên lịch tác vụ trên máy chủ từ xa và sau đó thăm dò để hoàn thành sử dụng ScheduledExecutorService#scheduleAtFixedRate
. Khi tác vụ hoàn tất, nó sẽ tải xuống kết quả. Tôi muốn trả lại số Future
cho người gọi để họ có thể quyết định thời gian và thời gian chặn và cung cấp cho họ tùy chọn hủy tác vụ.CompletableFuture # whenComplete không được gọi nếu sau đóApply được sử dụng
Vấn đề của tôi là nếu khách hàng hủy bỏ Future
được trả về theo phương pháp download
, thì khối whenComplete
không thực thi. Nếu tôi xóa thenApply
. Rõ ràng là tôi hiểu nhầm điều gì đó về thành phần Future
... Tôi nên thay đổi điều gì?
public Future<Object> download(Something something) {
String jobId = schedule(something);
CompletableFuture<String> job = pollForCompletion(jobId);
return job.thenApply(this::downloadResult);
}
private CompletableFuture<String> pollForCompletion(String jobId) {
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
CompletableFuture<String> completionFuture = new CompletableFuture<>();
ScheduledFuture<?> checkFuture = executor.scheduleAtFixedRate(() -> {
if (pollRemoteServer(jobId).equals("COMPLETE")) {
completionFuture.complete(jobId);
}
}, 0, 10, TimeUnit.SECONDS);
completionFuture
.whenComplete((result, thrown) -> {
System.out.println("XXXXXXXXXXX"); //Never happens unless thenApply is removed
checkFuture.cancel(true);
executor.shutdown();
});
return completionFuture;
}
Cùng lưu ý, nếu tôi làm:
return completionFuture.whenComplete(...)
thay vì
completionFuture.whenComplete(...);
return completionFuture;
whenComplete
cũng không bao giờ được thực thi. Điều này có vẻ rất phản đối với tôi. Không nên hợp lý Future
trả lại bởi whenComplete
là một trong những tôi nên giữ?
EDIT:
tôi đã thay đổi mã của tôi để rõ ràng back-tuyên truyền việc hủy bỏ. Đó là đáng ghê tởm và không thể đọc được, nhưng nó hoạt động và tôi không thể tìm thấy một cách tốt hơn:
public Future<Object> download(Something something) throws ChartDataGenException, Exception {
String jobId = schedule(report);
CompletableFuture<String> job = pollForCompletion(jobId);
CompletableFuture<Object> resulting = job.thenApply(this::download);
resulting.whenComplete((result, thrown) -> {
if (resulting.isCancelled()) { //the check is not necessary, but communicates the intent better
job.cancel(true);
}
});
return resulting;
}
Nó thậm chí không nhập khối 'whenComplete'. Tôi đặt một điểm ngắt và một 'System.out.print' bên trong, và cũng không có breakpoint được nhấn cũng không dòng được in. Cả hai xảy ra nếu tôi xóa bit 'thenApply'. – kaqqao
Theo sự hiểu biết của tôi, nó phải ngược lại những gì bạn báo cáo. 'completionFuture.whenComplete()' là một hàm thuần túy và không nên thay đổi bất cứ thứ gì theo cách 'completionFuture' tự hoạt động. Nếu bạn không trả lại kết quả của 'whenComplete', nó sẽ trở thành không thể truy cập và phải tuân theo GC. –
Hoàn toàn đồng ý. Nhưng đây là những gì tôi nhìn thấy ... Nếu trả về kết quả của 'whenComplete', và' hủy' nó ngay lập tức, tôi không nhận được XXXXX trong giao diện điều khiển. Mặt khác, nếu tôi trả lại 'completeFuture' ban đầu và' cancel' _that_, tôi làm. – kaqqao