2010-05-25 32 views
11

Khi tôi tạo một chuỗi bằng cách gọi ScheduledExecutorService.schedule(), nó không bao giờ chấm dứt sau khi thực hiện tác vụ được lập biểu.Tại sao luồng được khởi động bởi ScheduledExecutorService.schedule() không bao giờ chấm dứt?

Ví dụ chương trình sau đây không bao giờ bỏ:

public static void main(String[] args) { 
    ScheduledFuture scheduledFuture = 
     Executors.newSingleThreadScheduledExecutor().schedule(new Callable() { 

    public Void call() { 
     doSomething(); 
     return null; 
    } 

    }, 1, TimeUnit.SECONDS); 
} 

public static void doSomething() { 
} 

Đây có phải là một lỗi JDK, hoặc đã làm tôi chỉ bỏ lỡ một cái gì đó?

+0

Điều gì đang xảy ra trong doSomething()? –

Trả lời

2

Bạn cần gọi số scheduledExecutorService.shutdown() để ngừng thực hiện. Nếu không, nó sẽ được khởi động lại sau mỗi giây.

(CHỈNH SỬA: xem nhận xét)

+2

Nên gọi scheduledExecutorService.shutdown() thay vì scheduleFuture.shutdown(), và ScheduledExecutorService.schedule() gọi là hành động một-shot, sẽ không bao giờ được khởi động lại. – moonese

7

Tác vụ đã lên lịch đang được thực hiện hoặc đang chờ thực hiện.

Nếu tác vụ đang đợi để được thực hiện, future.cancel() sẽ ngăn không cho nó được thực hiện (cả hủy (đúng)/hủy (sai)).

Nếu tác vụ đã được thực hiện, future.cancel(false) sẽ không có hiệu lực. future.cancel(true) sẽ làm gián đoạn chuỗi đang thực hiện tác vụ đó. Việc này có ảnh hưởng đến bạn hay không, ai sẽ thực hiện nhiệm vụ đó. Tác vụ có thể hoặc không thể phản hồi gián đoạn tùy thuộc vào việc triển khai.

Để làm cho tác vụ của bạn đáp ứng yêu cầu hủy, bạn phải triển khai doSomething() để nó sẽ phản hồi sự gián đoạn.

Về cơ bản có hai cách để làm điều này:

1.Check gián đoạn cờ trong logic của bạn

public void doSomething(){ 
    stuff(); 
    //Don't use Thread.interrupt() 
    if(Thread.currentThread().isInterrupted()){ 
     // We have an interruption request, possibly a cancel request 
     //Stop doing what you are doing and terminate. 
     return; 
    } 
    doLongRunningStuff(); 
} 

Bạn thỉnh thoảng phải kiểm tra cờ gián đoạn, và nếu bị gián đoạn, dừng lại những gì bạn đang làm và quay lại. Hãy chắc chắn sử dụng Thread.isInterrupted() và không Thread.interrupt() cho kiểm tra.

2.Act khi ngoại lệ Interrupted

public void doSomething(){ 
    try{ 
     stuff(); 
    }catch(InterruptedException e){ 
     // We have an interruption request, possibly a cancel request 

     // First, preserve Interrupted Status because InterruptedException clears the 
     // interrupted flag 
     Thread.currentThread.interrupt(); 

     // Now stop doing your task and terminate 
     return; 
    } 

    doLongRunningStuff(); 
} 

Khi bạn có bất kỳ phương pháp mà ném InterruptedException, hãy chắc chắn để ngăn chặn những gì bạn làm và chấm dứt khi một được ném.

Khi bạn thực hiện các phương pháp theo cách này, bạn có thể gọi future.cancel (true) để hủy việc thực thi tác vụ đang chạy.

+0

Làm thế nào để tắt lịch biểu sau khi lệnh được gọi? Để giải phóng tài nguyên luồng. Sau khi tất cả, nhiệm vụ được tạo ra bởi lịch trình thực hiện một lần. – Nickolas

+0

@ Nickolas: Không chắc chắn ý bạn là gì, nhưng nếu bạn muốn nói một nhiệm vụ được lên kế hoạch để chạy một lần (sau khi trì hoãn vv) VÀ nó đã hoàn thành, thì nhiệm vụ sẽ dừng lại (và giải phóng luồng). Nếu không thì câu trả lời của tôi vẫn áp dụng. –

+1

Đây là câu trả lời hay nhưng đối với một câu hỏi khác. Vấn đề không phải là làm thế nào để chấm dứt nhiệm vụ - OP tuyên bố rõ ràng rằng nhiệm vụ là một nop - nhưng làm thế nào để chấm dứt thread được sử dụng để chạy nhiệm vụ. – oberlies

5

Chương trình của bạn không bao giờ chấm dứt vì bạn tạo ScheduledExecutorService, chứa một nhóm luồng, nhưng bạn không bao giờ tắt dịch vụ. Do đó, các luồng người dùng trong nhóm luồng không bao giờ bị chấm dứt, và do đó máy ảo tiếp tục chạy mãi mãi.

Để giải quyết vấn đề này, bạn cần gọi số shutdown() trên dịch vụ thi hành. Điều này thậm chí có thể được thực hiện trực tiếp sau khi lập lịch công việc bạn muốn thực hiện:

public static void main(String[] args) { 
    ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); 
    ScheduledFuture scheduledFuture = executorService.schedule(new Callable() { 

    public Void call() { 
     doSomething(); 
     return null; 
    } 

    }, 1, TimeUnit.SECONDS); 
    executorService.shutdown(); 
} 

Thao tác này sẽ thực hiện tác vụ theo lịch bình thường và sau đó chấm dứt chuỗi trong hồ bơi.

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