2010-06-23 30 views
5

Từ các bài đọc của tôi, có vẻ như ScheduledExecutorService là cách đúng để bắt đầu và dừng bộ hẹn giờ trong Java.sử dụng ScheduledExecutorService để bắt đầu và dừng hẹn giờ

Tôi cần chuyển một số mã bắt đầu và dừng hẹn giờ. Đây không phải là một bộ đếm thời gian định kỳ. Mã này, dừng bộ hẹn giờ trước khi bắt đầu. Vì vậy, hiệu quả mỗi bắt đầu thực sự là một khởi động lại(). Tôi đang tìm đúng cách để làm điều này bằng cách sử dụng ScheduledExecutorService. Đây là những gì tôi nghĩ ra. Looking for ý kiến ​​và cái nhìn sâu sắc vào những thứ tôi đang thiếu:

ScheduledExecutorService _Timer = Executors.newScheduledThreadPool(1); 
ScheduledFuture<?> _TimerFuture = null; 

private boolean startTimer() { 
    try { 
     if (_TimerFuture != null) { 
      //cancel execution of the future task (TimerPopTask()) 
      //If task is already running, do not interrupt it. 
      _TimerFuture.cancel(false); 
     } 

     _TimerFuture = _Timer.schedule(new TimerPopTask(), 
             TIMER_IN_SECONDS, 
             TimeUnit.SECONDS); 
     return true; 
    } catch (Exception e) { 
     return false; 
    } 
} 

private boolean stopTimer() { 
    try { 
     if (_TimerFuture != null) { 
      //cancel execution of the future task (TimerPopTask()) 
      //If task is already running, interrupt it here. 
      _TimerFuture.cancel(true); 
     } 

     return true; 
    } catch (Exception e) { 
     return false; 
    } 
} 

private class TimerPopTask implements Runnable { 
    public void run() { 
     TimerPopped(); 
    } 
} 

public void TimerPopped() { 
    //Do Something 
} 

tia, rúp

+0

Mã như được viết sẽ không biên dịch: _batchTimer trong startTimer() không được khai báo ở bất kỳ đâu. Sẽ rất hữu ích nếu bạn có thể tìm hiểu chi tiết hơn về các hành vi mong đợi: giá trị trả về từ startTimer và stopTimer là gì? Tại sao bạn muốn start/stopTimer có khả năng chặn cuộc gọi? – Sbodd

+0

@Sbodd, khi tôi bắt đầu hẹn giờ, nếu đã có bộ hẹn giờ chạy, tôi muốn dừng lại, để tôi không có hai đồng hồ bấm giờ cùng lúc. Tôi nghĩ rằng thay vì get() ở đó, tôi chỉ cần gọi hủy() trong trường hợp tương lai. – rouble

Trả lời

3

này trông giống như một vấn đề:

private boolean startTimer() { 
    // ...... 
     if (_TimerFuture != null) { 
      _TimerFuture.cancel(false); 
     } 

     _TimerFuture = _Timer.schedule(new TimerPopTask(), 
             TIMER_IN_SECONDS, 
             TimeUnit.SECONDS); 
    // ...... 
} 

Vì bạn đang đi qua một sai phải hủy bỏ, các cũ _TimerFuture có thể không bị hủy nếu tác vụ đang chạy. Một cái mới được tạo ra anyway (nhưng nó sẽ không chạy đồng thời bởi vì ExecutorService của bạn có kích thước hồ bơi cố định là 1). Trong mọi trường hợp, điều đó không có vẻ giống như hành vi mong muốn của bạn khi khởi động lại bộ hẹn giờ khi startTimer() được gọi.

Tôi sẽ nghiên cứu lại một chút. Tôi sẽ làm cho dụ TimerPopTask là điều bạn "hủy bỏ", và tôi sẽ rời khỏi ScheduledFutures một mình một khi họ được tạo ra:

private class TimerPopTask implements Runnable { 
    //volatile for thread-safety 
    private volatile boolean isActive = true; 
    public void run() { 
     if (isActive){ 
      TimerPopped(); 
     } 
    } 
    public void deactivate(){ 
     isActive = false; 
    } 
} 

sau đó tôi sẽ giữ lại trường hợp của TimerPopTask chứ không phải là trường hợp của ScheduledFuture và sắp xếp lại startTimer phương pháp thusly:

private TimerPopTask timerPopTask; 

private boolean startTimer() { 
    try { 
     if (timerPopTask != null) { 
      timerPopTask.deactivate(); 
     } 

     timerPopTask = new TimerPopTask(); 
     _Timer.schedule(timerPopTask, 
         TIMER_IN_SECONDS, 
         TimeUnit.SECONDS); 
     return true; 
    } catch (Exception e) { 
     return false; 
    } 
} 

(. sửa đổi Tương tự như stopTimer() phương pháp)

bạn có thể muốn khuấy động số lượng các đề nếu bạn thực sự dự đoán nee ding để 'khởi động lại' bộ đếm thời gian trước khi bộ đếm thời gian hiện tại hết hạn:

private ScheduledExecutorService _Timer = Executors.newScheduledThreadPool(5); 

Bạn có thể muốn đi với một cách tiếp cận lai, lưu giữ tài liệu tham khảo cho cả TimerPopTask hiện như tôi đã mô tả và cũng để các ScheduledFuture hiện tại và tận dụng tối nỗ lực để hủy bỏ nó và giải phóng thread nếu có thể, hiểu rằng nó không được đảm bảo để hủy bỏ.

(Lưu ý:.. Này tất cả các giả định startTimer() và stopTimer() các cuộc gọi phương pháp được giới hạn trong một chủ đề chính duy nhất, và chỉ có TimerPopTask trường được chia sẻ giữa các chủ đề Nếu không, bạn sẽ cần biện pháp bảo vệ bổ sung)

+0

điểm tốt. Hãy để tôi hỏi bạn điều này, nói rằng một nhiệm vụ đang chạy. Tác vụ mới được tạo và được lên lịch để chạy TIMER_IN_SECONDS giây sau đó. Thời gian này (TIMER_IN_SECONDS giây) bắt đầu khi nào? Liệu nó bắt đầu ngay sau đó, khi lịch trình() được gọi là HOẶC nó bắt đầu khi có một chủ đề miễn phí trong hồ bơi thread? – rouble

+0

Thời gian trễ TIMER_IN_SECONDS bắt đầu 'ngay bây giờ' ngay khi lịch biểu() được gọi.Nhiệm vụ được đảm bảo để bắt đầu không sớm hơn sự chậm trễ, tuy nhiên, nó có thể bắt đầu sau này (tùy thuộc vào một phần về tính khả dụng của luồng). Từ javadoc cho ScheduledThreadPoolExecutor: "Các tác vụ bị trì hoãn thực hiện không sớm hơn chúng được kích hoạt, nhưng không có bất kỳ đảm bảo thời gian thực nào về thời gian, sau khi chúng được kích hoạt, chúng sẽ bắt đầu." –

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