2011-06-27 29 views
20

Đối với thực hiện nhiệm vụ định kỳ, tôi nhìn vào TimerScheduledThreadPoolExecutor (với một chủ đề duy nhất) và quyết định sử dụng sau này, bởi vì trong reference for Executors.newSingleThreadScheduledExecutor(), nó nói:Tại sao một ScheduledExecutorService không chạy một nhiệm vụ một lần nữa sau khi một ngoại lệ được ném?

Lưu ý tuy nhiên rằng nếu chủ đề duy nhất này chấm dứt do một sự thất bại trong quá trình thực hiện trước khi tắt máy, một cái mới sẽ thay thế nếu cần thiết để thực hiện các nhiệm vụ tiếp theo.

Kế hoạch của tôi là sử dụng điều này như một biện pháp bảo vệ chống lại các trường hợp ngoại lệ chưa được nắm bắt trong một đoạn mã theo dõi mà tôi muốn theo dõi các hoạt động khác. Tôi muốn chắc chắn và viết bài kiểm tra dưới đây, điều này nhanh chóng thất bại. Có vẻ như tôi đã đưa ra những giả định sai lầm, hoặc có điều gì đó sai về thử nghiệm của tôi?

Dưới đây là các mã:

@Test 
public void testTimer() { 
    final AtomicInteger cTries = new AtomicInteger(0); 
    final AtomicInteger cSuccesses = new AtomicInteger(0); 

    TimerTask task = new TimerTask() { 
     @Override 
     public void run() 
     { 
      cTries.incrementAndGet(); 
      if (true) { 
       throw new RuntimeException(); 
      } 
      cSuccesses.incrementAndGet(); 
     } 
    }; 

    /* 
    Timer t = new Timer(); 
    t.scheduleAtFixedRate(task, 0, 500); 
    */ 
    ScheduledExecutorService exe = Executors.newSingleThreadScheduledExecutor(); 
    exe.scheduleAtFixedRate(task, 0, 500, TimeUnit.MILLISECONDS); 
    synchronized (this) { 
     try { 
      wait(3000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. 
     } 
    } 
    exe.shutdown(); 
    /* 
    t.purge(); 
    */ 
    Assert.assertEquals(cSuccesses.get(), 0); 
    Assert.assertTrue(cTries.get() > 1, String.format("%d is not greater than 1. :(", cTries.get())); 
} 
+0

Tôi biết, tôi có thể quấn một thứ (Có thể ném) xung quanh, nhưng kế hoạch của tôi là bằng cách nào đó bảo vệ tôi khỏi bản thân mình. –

+5

nó sẽ có vấn đề đối với mã khung như thế này để giả sử nó có thể khởi động lại một cách an toàn một công việc thất bại - thực tế là nó không thành công với một ngoại lệ có nghĩa là dữ liệu có thể bị bỏ lại ở bất kỳ trạng thái nào, và có khả năng sẽ không an toàn để khởi động lại công việc. –

+3

Trích dẫn về bắt đầu một chuỗi mới là cho phép các công việc khác tiếp tục chạy, ngay cả khi một lỗi không thành công –

Trả lời

22

Khi một nhiệm vụ lặp đi lặp lại đã ném một ngoại lệ còn tự do nó được giả định là đã chết hoặc được trong tình trạng lỗi. Đó là một chút của một gotcha rằng nó cũng không âm thầm trừ khi bạn kiểm tra tương lai để có được lỗi/ngoại lệ.

Bạn phải bắt ngoại lệ nếu bạn không muốn giết nhiệm vụ lặp lại.


Như matt b chỉ ra trong các bình luận trên,

nó sẽ được khó giải quyết cho mã khuôn khổ như thế này để cho rằng nó có thể an toàn khởi động lại một công việc thất bại - thực tế là nó thất bại với một ngoại lệ có nghĩa là dữ liệu có thể bị bỏ lại ở bất kỳ trạng thái nào và có khả năng sẽ không an toàn để khởi động lại công việc.

+0

Điều này vẫn áp dụng được không? Trong Spring boot 1.5.3, trình xử lý lỗi mặc định cho các nhiệm vụ lặp lại là [LOG_AND_SUPRESS_ERROR_HANDLER] (http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/scheduling/support/TaskUtils.html# LOG_AND_SUPPRESS_ERROR_HANDLER) sẽ không xóa @Scheduled khỏi hàng đợi thi hành. –

+0

Tôi đồng ý rằng bạn nên lập trình mã để bỏ qua các ngoại lệ và tự động khởi động lại, nhưng tôi có thể lập trình một dịch vụ RESTful mà tôi có thể sử dụng để khởi động lại trình lên lịch sau khi tôi khắc phục sự cố theo cách thủ công không? – jDub9

+0

@ jDub9 bạn có thể. Không có vấn đề gì khi tạo một ExecutorService mới hoặc một nhiệm vụ mới khi bạn sẵn sàng chạy lại. –

5

matt b đã đưa ra lý do.

nó sẽ là vấn đề đối với mã khuôn khổ như thế này để cho rằng nó có thể an toàn khởi động lại một công việc thất bại - thực tế là nó thất bại với một ngoại lệ có nghĩa là dữ liệu có thể đã bị bỏ lại trong bất kỳ loại nhà nước, và có khả năng sẽ không an toàn để khởi động lại công việc.



Cần lưu ý rằng được viết trong tài liệu của ScheduledExecutorService

Nếu bất kỳ thực hiện các nhiệm vụ gặp một ngoại lệ, sau hành đang bị đàn áp.

Và như là Michael Krusse nói, điểm về việc tạo chuỗi mới là cho phép các tác vụ khác tiếp tục chạy.

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