2012-11-01 28 views
12

Ok, vì vậy tôi biết câu trả lời/nhận xét đầu tiên ở đây sẽ là" sử dụng một số ExecutorService và sử dụng invokeAll ". Tuy nhiên, có một lý do chính đáng (mà tôi sẽ không cho người khác) để chúng tôi giữ riêng các hồ sợi.Cách đợi danh sách `Tương lai` được tạo bằng cách sử dụng `ExecutorServices` khác nhau

Vì vậy, tôi có một danh sách các hồ bơi chủ đề (ExecutorServices) và những gì tôi cần làm là gọi Callable khác nhau trên mỗi nhóm hồ sơ bằng cách sử dụng submit (không có vấn đề ở đó). Bây giờ tôi có bộ sưu tập này gồm Future trường hợp, mỗi phiên bản được tạo trên ExecutorService riêng biệt và tôi muốn đợi tất cả chúng hoàn thành (và có thể cung cấp thời gian chờ mà không được hủy bỏ).

Có lớp học hiện tại nào sẽ thực hiện việc này hay không (bao gồm danh sách các trường hợp Future và chờ đợi cho đến khi tất cả được thực hiện)? Nếu không, đề xuất về một cơ chế hiệu quả sẽ được đánh giá cao.

Nghĩ đến việc gọi get với thời gian chờ cho mỗi lần nhưng phải tính toán tổng thời gian được chuyển cho mỗi cuộc gọi.

Tôi thấy bài đăng này Wait Until Any of Future is Done nhưng điều này mở rộng Future thay vì gói một danh sách.

+0

cho mỗi danh sách đó và khi lần cuối cùng được thực hiện - như họ nói –

+0

Cập nhật bài đăng để làm rõ rằng thời gian chờ là vấn đề và tôi hy vọng không sáng tạo lại bánh xe trong vấn đề đó. –

+0

tốt nếu bạn đọc những tài liệu java tiện lợi, bạn sẽ thấy rằng bạn có thể AwaitTermination và thiết lập thời gian chờ sau đó khi bạn gửi các nhiệm vụ của bạn, bạn có thể gửi nó tắt và nếu nhiệm vụ không hoàn thành trong thời gian nó bị tắt máy sau khi hết thời gian chờ wabamzorz ur! !!! –

Trả lời

16

mỗi Louis' bình luận, những gì tôi đang tìm kiếm được Futures.successfulAsList

này cho phép tôi chờ đợi cho tất cả để hoàn thành và sau đó kiểm tra cho bất kỳ tương lai mà không thành công.

Nguyên tắc dung nham!

2

Tôi không nghĩ JDK cung cấp API trực tiếp cho phép bạn làm điều đó. Tuy nhiên, tôi nghĩ nó cũng không kém phần đơn giản để tạo ra một phương thức đơn giản để thực hiện điều này. Bạn có thể muốn xem xét việc thực hiện AbstractExecutorService.invokeAll() để có được một ý tưởng rằng điều này có thể được thực hiện.

Về cơ bản, bạn sẽ gọi đến future.get() trên mỗi tương lai, giảm thời gian chờ đợi để đợi kết quả mỗi lần và trước khi trở về từ phương thức hủy tất cả các tương lai chưa thanh toán.

+0

+1 Concur. Tôi đã nghĩ về điều đó và đưa nó vào bài viết của tôi như một cơ chế rõ ràng. Tôi đã hy vọng có một cơ chế tốt hơn/đã được thực hiện và người khác biết. –

+0

Đó có thể là một triển khai tốt như bạn có thể nhận được. Nó sẽ được đơn giản cho những người sáng tạo JDK để cung cấp đó như là một phương pháp độc lập (tĩnh). Việc triển khai khác có thể liên quan đến việc sử dụng dịch vụ hoàn thành và chờ đợi theo thứ tự các nhiệm vụ được hoàn thành. Tuy nhiên, mã trở nên liên quan nhiều hơn với ít lợi ích bổ sung. – sjlee

1

Có lẽ tôi đã không thực sự hiểu. Tuy nhiên, với tôi, nó vẫn nghe có vẻ đơn giản như

public <V> List<V> get(List<Future<V>> futures, long timeout, TimeUnit unit) 
      throws InterruptedException, ExecutionException, TimeoutException { 
    List<V> result = new ArrayList<V>(); 
    long end = System.nanoTime() + unit.toNanos(timeout); 
    for (Future<V> f: futures) { 
     result.add(f.get(end - System.nanoTime(), TimeUnit.NANOSECONDS)); 
    } 
    return result; 
} 

Tôi có sai với điều đó không?

Câu hỏi mà bạn liên kết phức tạp hơn nhiều, tôi nghĩ, vì họ chỉ muốn chờ nhanh nhất, và tất nhiên không có ý tưởng nào sẽ nhanh nhất.

+0

+1 Vấn đề với điều này là 'get' có thể ném một ngoại lệ. Thay đổi nó để trả lại 'Tương lai 'sau khi tất cả chúng được thực hiện sẽ giúp ích. Ngoài ra, nó không xử lý việc tắt máy. Đây là việc thực hiện rõ ràng, tôi đã muốn xem nếu có một cái gì đó sạch hơn/đã được thực hiện như thử nghiệm. –

1

Điều này có thể sử dụng một số dọn dẹp, nhưng nó sẽ giải quyết vấn đề của bạn. (Một số đóng gói bỏ qua thời gian và không gian):

public static <T> LatchWithWrappedCallables<T> wrapCallables(Collection<Callable<T>> callablesToWrap) 
{ 
    CountDownLatch latch = new CountDownLatch(callablesToWrap.size()); 
    List<Callable<T>> wrapped = new ArrayList<Callable<T>>(callablesToWrap.size()); 
    for (Callable<T> currCallable : callablesToWrap) 
    { 
     wrapped.add(new CallableCountdownWrapper<T>(currCallable, latch)); 
    } 

    LatchWithWrappedCallables<T> returnVal = new LatchWithWrappedCallables<T>(); 
    returnVal.latch = latch; 
    returnVal.wrappedCallables = wrapped; 
    return returnVal; 
} 

public static class LatchWithWrappedCallables<T> 
{ 
    public CountDownLatch latch; 
    public Collection<Callable<T>> wrappedCallables; 
} 

public static class CallableCountdownWrapper<T> implements Callable<T> 
{ 
    private final Callable<T> wrapped; 

    private final CountDownLatch latch; 

    public CallableCountdownWrapper(Callable<T> wrapped, CountDownLatch latch) 
    { 
     this.wrapped = wrapped; 
     this.latch = latch; 
    } 

    @Override 
    public T call() throws Exception 
    { 
     try 
     { 
      return wrapped.call(); 
     } 
     finally 
     { 
      latch.countDown(); 
     } 
    } 
} 

Sau đó, mã của bạn sẽ gọi nó là như thế này:

Collection<Callable<String>> callablesToWrap = [Your callables that you need to wait for here]; 
LatchWithWrappedCallables<String> latchAndCallables = wrapCallables(callablesToWrap); 

[Submit the wrapped callables to the executors here] 

if(latchAndCallables.latch.await(timeToWaitInSec, TimeUnit.SECONDS)) 
{ 
    [Handling for timeout here] 
} 
+0

Và trên suy nghĩ thứ hai, tôi nghĩ rằng tôi có thể sẽ chờ đợi sự chờ đợi trực tiếp vào lớp LatchWithWrappedCallables để làm cho nó dễ dàng hơn. (Và có, "LatchWithWrappedCallables" là một tên khủng khiếp!) –

+0

Tôi sẽ đưa ra một số suy nghĩ sâu hơn vào ngày mai để xem liệu nó có phù hợp với nhu cầu của tôi hay không. Cảm ơn. –

+0

Tốt. Tôi cũng cần xem xét điều ListenableFuture. –

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