2010-01-21 28 views
5

Tôi muốn quản lý một danh sách các đối tượng tương lai được trả về bởi TaskExecutor của tôi.
Tôi đã một cái gì đó như thế nàyJava Thread - hành vi lạ Thread.interrupted() và tương lai.cancel (true)

List<Future<String>> list 

void process(ProcessThis processThis) {  
    for (...) { 
     Future<String> future = taskExecutor.submit(processThis); 
     list.add(future) 
    } 
} 


void removeFutures() { 
    for(Future future : list) { 
     assert future.cancel(true); 
} 

ProcessThis là một nhiệm vụ mà thực hiện Callable < String> và kiểm tra Thread.interrupted() tình trạng

public String call() { 
     while (true) { 
      if (Thread.interrupted()) { 
       break; 
      } 
      doSomething(); 
     } 
    } 

Bây giờ vấn đề là chỉ là một tập hợp con của các Threads đồng thời trả về 'true' khi Thread.interrupted() được gọi.
Xác nhận trong removeFutures() trả về giá trị true cho mỗi tương lai bị xóa (tôi đã chọn isDone() và isCompleted() là
Số lượng Chủ đề bị gián đoạn là ngẫu nhiên. đôi khi 2 ...
Tôi thực sự không hiểu vấn đề ở đâu. Nếu tôi gọi future.cancel (true) và điều này trả về true ... và sau đó tôi kiểm tra Thread.interrupted (điều này được gọi chỉ một lần), tôi mong đợi này để trả lại sự thật là tốt.
Bất kỳ ý tưởng về những gì tôi bị mất?

tôi đang trên build java 1.6.0_02-b05

Trả lời

2

ít nhất, bạn nên khôi phục lại interr uption flag để làm cho taskExecutor nhận biết được sự gián đoạn của luồng:

public String call() { 
    while (true) { 
     if (Thread.interrupted()) { 
      Thread.currentThread().interrupt(); 
      break; 
     } 
     doSomething(); 
    } 
} 
+0

cảm ơn phản hồi của bạn. điểm của việc này là gì? Nếu Thread.interrupted() trả về true, tôi sẽ phá vỡ chu kỳ while và về cơ bản tôi sẽ hủy thread. Vấn đề là đôi khi Thread.interrupted() trả về 'false' ngay cả khi tương lai liên quan.cancel (true) trả về true. Dòng bạn đã chỉnh sửa thậm chí không thể đạt được tại thời điểm đó. – marts

+0

Sau đó cờ gián đoạn có thể bị mất ở đâu đó trong 'doSomething()' (vì lý do tương tự - một cái gì đó đặt lại cờ và không khôi phục lại). Đó là, mẫu trong câu trả lời của tôi là một nguyên tắc cơ bản mà nên được sử dụng để tránh bị mất ngắt – axtavt

+0

Nếu đó là trường hợp ('tránh bị gián đoạn bị ngắt') tôi không thể sử dụng một cái gì đó như Thread.currentThread(). IsInterrupted() thay vì phải khôi phục trạng thái ngắt mỗi khi tôi sử dụng Thread.interrupted(). (BTW có một lỗi với điều này: http://stackoverflow.com/questions/2012259/) Tôi không phải đối phó với tình trạng gián đoạn trong doSomething. – marts

2

Một vấn đề tiềm năng mà ngắt thường bị nuốt chửng. Vì vậy, một nơi nào đó sâu trong doSomething() (hoặc thậm chí trong lớp tải), một gián đoạn có thể bị bắt bởi, nói, wait() và sau đó bị loại bỏ bởi 'bất cẩn' mã. Gián đoạn là ác, IMO.

Có thể đáng để kiểm tra xem tất cả các nhiệm vụ của bạn có thực sự chạy tại thời điểm hủy hay không.

6

Hãy lưu ý rằng Thread.interrupted() trả lại trạng thái bị gián đoạn hiện tại và sau đó xóa nó, vì vậy tất cả các lời gọi trong tương lai sẽ trả về false. Những gì bạn muốn có lẽ là Thread.currentThread().isInterrupted().

Cũng lưu ý rằng future.cancel(true) thường sẽ chỉ trả về false nếu tác vụ đã được hoàn thành hoặc hủy. Nếu nó trả về true, đó là không đảm bảo rằng nhiệm vụ thực sự sẽ bị hủy bỏ.

Điều gì đang xảy ra trong doSomething()? Có thể là một RuntimeException đang thoát ở đâu đó do ngắt. Bạn có cài đặt UncaughtExceptionHandler không? Nếu không, bạn sẽ cần phải chuyển số ThreadFactory đến số Executor sẽ đặt trình xử lý ngoại lệ và đăng nhập bất kỳ ngoại lệ nào bị thiếu.

+0

Tôi biết điều này. Tôi đang gọi Thread.interrupted() chỉ một lần sau thời gian {. Dù sao nếu nó trở về sự thật tôi phá vỡ; và giết Thread ngay lập tức (và tôi không chạm/kiểm tra ngắt ở bất cứ nơi nào khác). Tôi sẽ xem UncaughtExceptionHandler. cảm ơn vì ý kiến ​​của bạn . (BTW được nhận thức của lỗi này trong Thread.currentThread(). IsInterrupted() http://bugs.sun.com/view_bug.do?bug_id=6772683) – marts

+0

Hiện tại, bạn đang sử dụng chính xác Thread.interrupted() trong một cách thức an toàn. Tuy nhiên, nếu bạn không cần hành vi được cung cấp bởi phương thức đó, bạn không nên sử dụng nó như một người khác (hoặc chính bạn) có thể tái cấu trúc phương thức đó sao cho Thread.interrupted() được gọi theo cách làm mất hiệu lực xử lý ngắt . Nó an toàn hơn nhiều khi sử dụng Thread.currentThread(). IsInterrupted() nếu bạn có thể. – Kevin

+0

Xin chào Kevin. Bạn đã đúng nhưng do vấn đề giấy phép java tôi không thể cập nhật JVM hiện tại 1.6.0_02-b05. Tôi đang chạy trên một máy đa xử lý và JVM của tôi có thể bị ảnh hưởng bởi các lỗi tôi liên kết trong các bình luận trước đó (đây là một bài liên quan trong stackoverflow http://stackoverflow.com/questions/2012259/). Về ngoại lệ unhandled, nếu một RuntimeException thoát tôi có thể immagine rằng thread chết bởi riêng của mình, phải không? ở đây vấn đề của tôi là ngược lại .. họ không dừng lại. (hoặc ít nhất một tập con của chúng bị dừng) – marts