2009-07-24 12 views
6

Tôi chỉ bắt đầu xem xét Futures và ScheduledExecutorService trong Java, và tôi tự hỏi tại sao Callable của tôi không chạy theo lịch biểu tôi đã chỉ ra. Trong mã mẫu này, các cuộc gọi chạy một lần, nhưng các ứng dụng không bao giờ hoàn thành, cũng không phải nhiệm vụ chạy một lần nữa, đó là những gì tôi dự kiến ​​sẽ xảy ra (Tôi chắc chắn vấn đề là với kỳ vọng của tôi).Tìm kiếm rõ ràng trên Java ScheduledExecutorService và FutureTask

Runnables hoạt động tốt; Cuộc gọi dường như chặn mãi mãi, nhưng tôi không chắc tại sao .... Tôi đang thiếu gì?

Cảm ơn!

public class ExecutorExample { 

    /** 
    * @param args 
    * @throws ExecutionException 
    * @throws InterruptedException 
    */ 
    public static void main(String[] args) throws InterruptedException, ExecutionException { 

     ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5); 

     FutureTask<ArrayList<String>> ft1 = new FutureTask<ArrayList<String>>(new Callable<ArrayList<String>>(){ 
      @Override 
      public ArrayList<String> call() { 
       ArrayList<String> stuff = new ArrayList<String>(); 
       for(int i = 0;i<10;i++){ 
        String thing ="Adding " + i + " to result"; 
        stuff.add(thing); 
        System.out.println(thing); 

       } 
       return stuff; 
      }}); 

     scheduler.scheduleAtFixedRate(ft1, 0, 1, TimeUnit.SECONDS); 

     System.out.println(ft1.get()); 
     System.out.println(ft1.isDone()); 

    } 
} 

Trả lời

8

Vấn đề là FutureTask được sử dụng, và như tài liệu hướng dẫn các lớp học nói, "Một khi tính toán đã hoàn tất, việc tính toán có thể không được khởi động lại hoặc hủy bỏ."

Sau khi run phương thức FutureTask đã được gọi một lần, các yêu cầu tiếp theo trả về ngay lập tức, mà không ủy nhiệm cho ví dụ Callable của nhiệm vụ.

Chỉ có thể sử dụng Runnable làm tác vụ lặp lại và điều này không cho phép truyền lại kết quả. Thay vào đó, hãy cung cấp nhiệm vụ Runnable một cuộc gọi lại mà nó có thể gọi vào cuối phương thức run của nó, để báo cáo kết quả của mỗi lần thực hiện tác vụ trở lại với người nghe trong các chủ đề khác.

+1

Tôi không chắc chắn tôi làm theo điều này. FutureTask thực hiện Runnable, và tôi mong đợi nó sẽ gọi phương thức call() và lưu trữ kết quả. Sau đó, tôi sẽ nhận được() để chặn cho đến khi công việc được thực hiện hoặc trả về kết quả được lưu trong bộ nhớ cache ngay lập tức. Vì vậy, không phải lịch trình chạy FutureTask, dẫn đến cuộc gọi() và kết quả được lưu trữ để thu thập sau này? –

+1

Có, nhưng chỉ một lần. Bất kỳ lời gọi được lên lịch nào sau lần gọi đầu tiên sẽ gọi 'run' trên FutureTask, nhưng phương thức chạy" short-circuit "đó mà không gọi' call' trên Callable. Nhưng bộ lập lịch không nhận thức được điều này và tiếp tục chạy để gọi FutureTask, do đó chương trình không chấm dứt. – erickson

+0

Làm cho cảm giác hoàn hảo. Tôi đã đi xuống trong javadocs cho các Executors và ilk của nó và tôi hoàn toàn bỏ lỡ dòng rõ ràng đó trong FutureTask. Như một câu hỏi tiếp theo, nếu những gì tôi muốn xảy ra là kết quả của nhiệm vụ của tôi là một BlockingQueue được cập nhật, nó là thích hợp hơn để chỉ cần chuyển hàng đợi đó vào mỗi runnable, hoặc để thực hiện một người nghe sẽ sống bên ngoài runnable mà sau đó thao tác hàng đợi dựa trên kết quả? Cảm ơn một lần nữa –