2009-12-16 32 views
13

Tôi có một nhiệm vụ dài chạy, một cái gì đó như:Java chạy dài nhiệm vụ Chủ đề gián đoạn vs hủy cờ

public void myCancellableTask() { 
    while (someCondition) { 
     checkIfCancelRequested(); 
     doSomeWork(); 
    } 
} 

Nhiệm vụ có thể bị hủy bỏ (một hủy được yêu cầu và checkIfCancelRequested() kiểm tra hủy bỏ cờ). Nói chung khi tôi viết các vòng hủy như thế này, tôi sử dụng một lá cờ để chỉ ra rằng một yêu cầu hủy đã được yêu cầu. Nhưng, tôi biết tôi cũng có thể sử dụng Thread.interrupt và kiểm tra xem các thread đã bị gián đoạn. Tôi không chắc đó sẽ là cách tiếp cận ưa thích và tại sao, suy nghĩ?

cảm ơn,

Jeff

Trả lời

6

Interrupt sẽ nổ sợi ra khỏi một danh sách các điều kiện quy định chờ đợi. Cờ hủy của riêng bạn sẽ không. Nếu bạn muốn ngắt quãng thời gian chờ trên IO và các sự kiện, hãy sử dụng ngắt. Nếu không, hãy sử dụng của riêng bạn.

0

Tôi nghĩ rằng đó là vấn đề ưu tiên trong hầu hết các trường hợp. Cá nhân tôi sẽ dùng cờ làm bằng tay. Nó cho phép bạn kiểm soát nhiều hơn - ví dụ, theo cách này bạn đảm bảo rằng luồng của bạn không để lại một số đối tượng khác trong trạng thái không nhất quán. Bên cạnh đó, nếu hiệu suất thực sự quan trọng, hãy nhớ rằng việc sử dụng các ngoại lệ có chi phí cao (ngay cả khi nó không đáng kể trong 99% các trường hợp).

1

Tùy thuộc vào việc triển khai doSomeWork(). Đó là tính toán thuần túy hay không (tại bất kỳ điểm nào) có liên quan đến việc chặn các cuộc gọi API (chẳng hạn như IO)? Per câu trả lời của bmargulies, nhiều API chặn trong JDK là gián đoạn và sẽ truyền bá ngoại lệ bị gián đoạn lên ngăn xếp. Vì vậy, nếu công việc đòi hỏi phải có khả năng chặn các hoạt động, bạn cần phải tạm ngưng xem xét ngay cả khi bạn quyết định kiểm soát quy trình bằng cờ và phải nắm bắt và xử lý một cách thích hợp.

Ngoài ra, nếu dựa vào cờ, hãy đảm bảo cờ của bạn được khai báo với volatile ngữ nghĩa.

20

Một vấn đề với việc sử dụng ngắt là nếu bạn không kiểm soát tất cả các mã được thực thi, bạn chạy các nguy cơ của ngắt không làm việc "đúng" vì của người khác hiểu biết bị hỏng về cách xử lý ngắt trong họ thư viện. Đó là API invisibly xuất một API xung quanh việc xử lý interrupt s mà bạn trở nên phụ thuộc vào.

Trong ví dụ của bạn, giả sử doSomeWork là trong một JAR của bên thứ 3 và trông giống như:

public void doSomeWork() { 
    try { 
     api.callAndWaitAnswer() ; 
    } 
    catch (InterruptedException e) { throw new AssertionError(); } 
} 

Bây giờ bạn có để xử lý một AssertionError (hoặc bất cứ điều gì khác thư viện bạn đang sử dụng có thể ném). Tôi đã thấy các nhà phát triển có kinh nghiệm ném tất cả các loại vô nghĩa khi nhận các ngắt! Mặt khác, có thể phương pháp giống như sau:

public void doSomeWork() { 
    while (true) { 
     try { 
      return api.callAndWaitAnswer() ; 
     } 
     catch (InterruptedException e) { /* retry! */ } 
    } 
} 

Điều này "xử lý không đúng" làm gián đoạn chương trình của bạn lặp đi lặp lại vô thời hạn. Một lần nữa, đừng bỏ qua điều này là vô lý; có rất nhiều cơ chế xử lý ngắt bị gián đoạn ngoài kia.

Ít nhất bằng cờ của riêng bạn sẽ hoàn toàn ẩn đối với bất kỳ thư viện nào của bên thứ ba.

+1

Nội dung thú vị tại đây. Đó là tất cả các quá phổ biến để xem nuốt của gián đoạn hoặc chỉ cần đăng nhập và tiếp tục mà không cần đặt lại cờ ngắt. Tôi nghĩ mọi người cảm thấy thất vọng rằng đó là một ngoại lệ được kiểm tra mà họ không biết phải làm gì, vì vậy họ không làm gì cả. –

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