2015-01-02 14 views
7

Tôi đã gặp phải hành vi lạ của phương thức Java 8 CompletableFuture thenCompose. Tôi có hai xét nghiệm chỉ khác nhau theo thứ tự thực hiện. Cả hai bài kiểm tra mô phỏng thất bại trong CompletableFuture được tạo ra trong đóSau đó.Tại sao Java 8 CompletableFuture rồiSửa đổi tạo ra ngoại lệ khác nhau tùy thuộc vào thứ tự hoàn thành?

@Test 
public void completedAfter() { 
    CompletableFuture<String> future1 = new CompletableFuture<>(); 
    CompletableFuture<String> future2 = new CompletableFuture<>(); 

    future1.thenCompose(x -> future2).whenComplete((r, e) -> System.out.println("After: " + e)); 

    future1.complete("value"); 
    future2.completeExceptionally(new RuntimeException()); 
} 

@Test 
public void completedBefore() { 
    CompletableFuture<String> future1 = new CompletableFuture<>(); 
    CompletableFuture<String> future2 = new CompletableFuture<>(); 

    future1.complete("value"); 
    future2.completeExceptionally(new RuntimeException()); 

    future1.thenCompose(x -> future2).whenComplete((r, e) -> System.out.println("Before: " +e)); 
} 

Đầu ra là:

After: java.util.concurrent.CompletionException: java.lang.RuntimeException 
Before: java.lang.RuntimeException 

Câu hỏi đặt ra là, tại sao là ngoại lệ được bọc trong CompletionException trong một trường hợp nhưng không phải trong khác?

Cập nhật: Here là báo cáo lỗi liên quan. Nó đã được đánh dấu và giải quyết như một lỗi trong JDK.

+1

Bạn đã nhìn ListenableFuture ổi không? Nếu bạn không bị khóa vào khung công tác, tôi khuyên bạn nên sử dụng thực hiện của ổi. Theo quan điểm hoàn toàn của tôi, đó là tính năng hoàn chỉnh và dễ sử dụng hơn nhiều. Disclamer, tôi không có cách nào liên kết với Google. –

+1

Đã có rất nhiều lưu lượng truy cập trên Completablefuture trên danh sách sở thích đồng thời. Danh sách tháng 11 có thể khiến bạn quan tâm: http://cs.oswego.edu/pipermail/concurrency-interest/2014-November/subject.html – edharned

Trả lời

2

Có vẻ như một lỗi trong thư viện jdk.

Trong trường hợp "Sau", .thenCompose thêm nút hoàn thành ThenCopy vào tương lai mục tiêu, sau đó thực thi sau đó được kích hoạt bởi .completeExceptionally. Phương thức run của nút hoàn thành sẽ tìm ra ngoại lệ trong tương lai và gọi .internalComplete trên đích, kết thúc tất cả ngoại lệ thành CompletionException. Xem here cách nút được tạo và here cho nơi gói xảy ra.

Hiện tại, trong trường hợp Before, đường dẫn mã hoàn toàn khác. Vì tương lai đã được hoàn thành, .thenCompose không tạo thêm nút, nhưng ngay lập tức trả về một cuộc gọi lại ngay lập tức, và chỉ cần trả lại (tương lai thứ hai đã hoàn thành), sau đó bạn gọi .whenComplete, một lần nữa, không bận tâm để tạo một nút mới nút hoàn thành, nhưng chỉ đơn giản là invokes the callback ngay lập tức, cho nó ngoại lệ ban đầu từ tương lai thứ hai.

Boy, nhìn vào mã này, có rất nhiều ví dụ tôi muốn hiển thị cho các học sinh của tôi về những gì họ không bao giờ nên làm ...

+0

Tại sao lại có lỗi? Hành vi có vi phạm bất kỳ hợp đồng nào không? –

+0

@MarkoTopolnik Khá rõ ràng. Điều này phải làm với 'CompletionStage' phụ thuộc. Các phụ thuộc vào một giai đoạn đơn được sắp xếp bằng cách sử dụng các phương thức có tiền tố 'then'._ và _if tính toán của một giai đoạn chấm dứt đột ngột với một ngoại lệ hoặc lỗi, sau đó tất cả các giai đoạn phụ thuộc yêu cầu hoàn thành hoàn toàn đặc biệt, với một' CompletionException' đang nắm giữ ngoại trừ nguyên nhân của nó._ –

+0

@MarkoTopolnik Tôi không thấy nó được đề cập một cách rõ ràng ở bất cứ nơi nào mà tất cả ngoại lệ, được ném bởi tương lai sẽ được bao bọc thành 'CompletableException', nhưng tôi nghi ngờ ý định là chúng đôi khi * được bọc và đôi khi không, tùy thuộc vào ... cái gì? cpu tốc độ? Ý tôi là, hành vi này là không xác định. Có lẽ, một "lỗi" quá mạnh mẽ của một từ. Hãy gọi nó là "tính năng không mong muốn"? – Dima

Các vấn đề liên quan