Ai đang gọi phương thức Java Threadrupt () nếu tôi không gọi?


87

Tôi đã đọc và đọc lại Java Concurrency trong Thực tế, tôi đã đọc một số chủ đề ở đây về chủ đề này, tôi đã đọc bài báo của IBM Đối phó với InterruptException và có điều gì đó tôi chỉ đơn giản là không nắm được mà tôi nghĩ có thể bị hỏng thành hai câu hỏi:

  1. Nếu tôi không bao giờ tự mình làm gián đoạn các chuỗi khác, điều gì có thể kích hoạt Ngoại lệ bị gián đoạn ?

  2. Nếu tôi chưa bao giờ tự mình làm gián đoạn các chuỗi khác bằng cách sử dụng ngắt () (giả sử vì tôi đang sử dụng các phương tiện khác để hủy các chuỗi đang hoạt động của mình, chẳng hạn như thuốc độc và vòng lặp kiểu while (! Đã hủy) [như cả hai đã giải thích trong JCIP]), thì sao Vậy thì InterruptException có nghĩa là gì? Tôi phải làm gì khi bắt được một con? Tắt ứng dụng của tôi?

Câu trả lời:


50

Cơ chế ngắt luồng là cách ưa thích để một luồng (hợp tác) phản hồi yêu cầu dừng những gì nó đang làm. Bất kỳ luồng nào (bao gồm cả chính luồng mà tôi nghĩ) có thể gọi interrupt()trên một Chủ đề.

Trong thực tế, các trường hợp sử dụng thông thường interrupt()liên quan đến một số loại khuôn khổ hoặc trình quản lý yêu cầu một số luồng công nhân dừng những gì họ đang làm. Nếu luồng công nhân "nhận biết ngắt", nó sẽ thông báo rằng nó đã bị gián đoạn thông qua một ngoại lệ hoặc bằng cách kiểm tra định kỳ cờ bị ngắt của nó. Khi nhận thấy rằng nó đã bị gián đoạn, một chuỗi hoạt động tốt sẽ từ bỏ những gì nó đang làm và tự kết thúc.

Giả sử trường hợp sử dụng ở trên, mã của bạn có thể bị gián đoạn nếu nó được chạy trong khuôn khổ Java hoặc từ một chuỗi công nhân nào đó. Và khi nó bị gián đoạn, mã của bạn nên từ bỏ những gì nó đang làm và tự kết thúc bằng cách thích hợp nhất. Tùy thuộc vào cách mã của bạn được gọi, điều này có thể được thực hiện bằng cách trả về hoặc bằng cách ném một số ngoại lệ thích hợp. Nhưng nó có lẽ không nên gọi System.exit(). (Ứng dụng của bạn không nhất thiết biết lý do tại sao nó bị gián đoạn và chắc chắn nó không biết liệu có các luồng khác cần bị gián đoạn bởi khuôn khổ hay không.)

Mặt khác, nếu mã của bạn không được thiết kế để chạy dưới sự kiểm soát của một số khuôn khổ, bạn có thể tranh luận rằng đó InterruptedExceptionlà một ngoại lệ không mong muốn; tức là một con bọ. Trong trường hợp đó, bạn nên xử lý ngoại lệ như đối với các lỗi khác; ví dụ: bọc nó trong một ngoại lệ không được kiểm tra, và bắt và ghi lại nó vào cùng thời điểm bạn xử lý các ngoại lệ không được kiểm tra bất ngờ khác. (Ngoài ra, ứng dụng của bạn có thể đơn giản bỏ qua sự gián đoạn và tiếp tục làm những gì nó đang làm.)


1) Nếu tôi không bao giờ tự mình làm gián đoạn các chuỗi khác, điều gì có thể kích hoạt Ngoại lệ bị gián đoạn?

Một ví dụ là nếu các Runnableđối tượng của bạn được thực thi bằng cách sử dụng ExecutorServiceshutdownNow()được gọi trên dịch vụ. Và về lý thuyết, bất kỳ nhóm luồng hoặc khuôn khổ quản lý luồng nào của bên thứ 3 đều có thể làm điều gì đó như thế này một cách hợp pháp.

2) Nếu tôi không bao giờ tự mình ngắt các chuỗi khác bằng cách sử dụng ngắt () ... thì an InterruptedExceptioncó nghĩa là gì? Tôi phải làm gì khi bắt được một con? Tắt ứng dụng của tôi?

Bạn cần phân tích cơ sở mã để tìm ra những gì đang thực hiện các interrupt()cuộc gọi và tại sao. Khi bạn đã tìm ra điều đó, bạn có thể tìm ra những gì >> phần << ứng dụng của bạn cần làm.

Cho đến khi bạn biết lý do tại sao lại InterruptedExceptionbị ném, tôi khuyên bạn nên coi nó như một lỗi khó; ví dụ: in stacktrace vào tệp nhật ký và tắt ứng dụng. (Rõ ràng, đó không phải lúc nào cũng là câu trả lời đúng ... nhưng vấn đề là đây là "một lỗi", và nó cần được nhà phát triển / người bảo trì chú ý).

3) Làm cách nào để tìm ra ai / cái gì đang gọi interrupt()?

Không có câu trả lời tốt cho điều này. Cách tốt nhất tôi có thể đề xuất là đặt một điểm ngắt trên Thread.interrupt()và nhìn vào ngăn xếp cuộc gọi.


12

Nếu bạn quyết định tích hợp mã của mình với các thư viện khác, họ có thể gọi interrupt()mã của bạn. Ví dụ: nếu trong tương lai bạn quyết định thực thi mã của mình trong ExecutorService , thì điều đó có thể buộc phải tắt interrupt().

Nói một cách ngắn gọn, tôi không chỉ xem xét mã của bạn đang chạy ở đâu bây giờ mà còn xem nó có thể chạy trong ngữ cảnh nào trong tương lai. Ví dụ: bạn sẽ đặt nó trong một thư viện? Một container ? Người khác sẽ sử dụng nó như thế nào? Bạn sẽ sử dụng lại nó?


Tôi nghĩ chỉ có shutdownNow mới gọi phương thức ngắt (). Nó có đúng với việc tắt máy không?
Harinder

9

Như những người khác đã chỉ ra, làm gián đoạn một chuỗi (thực sự là làm gián đoạn cuộc gọi chặn) thường được sử dụng cho mục đích thoát sạch hoặc hủy một hoạt động đang diễn ra.

Tuy nhiên, bạn không nên coi một InterruptedExceptionmình như một "lệnh bỏ". Thay vào đó, bạn nên nghĩ về ngắt như một phương tiện để kiểm soát trạng thái đang chạy của các luồng, giống như cách làm Object.notify(). Tương tự như cách bạn kiểm tra trạng thái hiện tại sau khi thức dậy sau cuộc gọi tới Object.wait()(bạn không cho rằng việc đánh thức có nghĩa là điều kiện chờ của bạn đã được thỏa mãn), sau khi bị thúc vào một đoạn ngắt quãng, bạn nên kiểm tra lý do tại sao bạn bị gián đoạn . Thường có một cách để làm điều này. Ví dụ, java.util.concurrent.FutureTaskcó một isCancelled()phương pháp.

Mẫu mã:

public void run() {
    ....
    try {
        .... // Calls that may block.
    } catch (InterruptedException e) {
        if (!running) {  // Add preferred synchronization here.
            return; // Explicit flag says we should stop running.
        }
        // We were interrupted, but the flag says we're still running.
        // It would be wrong to always exit here. The interrupt 'nudge'
        // could mean something completely different. For example, it
        // could be that the thread was blocking on a read from a particular
        // file, and now we should read from a different file.
        // Interrupt != quit (not necessarily).
    }
    ....
}
public void stop() {
    running = false; // Add preferred synchronization here.
    myThread.interrupt();
}

3

Vấn đề của câu hỏi là "Tôi". "Tôi" thường đề cập đến một thể hiện duy nhất của một lớp. Ý tôi là, bất kỳ đoạn mã cấp thấp cụ thể nào (lớp) không nên dựa vào việc triển khai toàn bộ hệ thống. Đã nói rằng bạn đã thực hiện một số quyết định "kiến trúc" (như nền tảng nào để chạy trên).

Các gián đoạn không mong muốn có thể xảy ra từ JRE là các tác vụ bị hủy trong java.util.concurrentvà tắt các applet.

Xử lý ngắt luồng thường được viết không chính xác. Vì vậy, tôi đề nghị quyết định kiến ​​trúc để tránh gây ra sự gián đoạn nếu có thể. Tuy nhiên, các ngắt xử lý mã phải luôn được viết đúng. Không thể làm gián đoạn nền tảng bây giờ.


Xin chào Tom, tôi nhớ tên của bạn từ cljp;) Chà, chính xác là: Tôi chưa bao giờ phải tự mình thực hiện ngắt () ... Trừ khi tôi đang gặp phải InterruptException và cần xác nhận lại trạng thái bị gián đoạn nhưng đây vẫn chưa phải là 100% Rõ ràng với tôi. Tôi là người mới ở đây và ngạc nhiên bởi số lượng ủng hộ và câu trả lời / bình luận (cả câu đúng và sai): rõ ràng đó là một chủ đề không hề tầm thường hoặc ít nhất là thường không được giải thích rõ ràng. Điều đó nói lên rằng nhờ tất cả các bài đăng, tôi đang bắt đầu có một bức tranh rõ ràng hơn về những gì đang xảy ra :)
SyntaxT3rr0r

3

Bạn có thể học điều này bằng cách tạo lớp luồng (mở rộng java.lang.Thread) và interrupt()phương thức ghi đè của riêng mình , trong đó bạn ghi lại stacktrace, chẳng hạn như trường Chuỗi, rồi chuyển sang super.interrupt ().

public class MyThread extends Thread {

    public volatile String interruptStacktrace; // Temporary field for debugging purpose.

    @Override
    public void interrupt() {
        interruptStacktrace = dumpStack(); // You implement it somehow...

        super.interrupt();
    }
}

1

Như đã đề cập, một thư viện khác có thể làm gián đoạn chuỗi của bạn. Ngay cả khi thư viện không có quyền truy cập rõ ràng vào các luồng từ mã của bạn, họ vẫn có thể lấy danh sách các luồng đang chạy và ngắt chúng theo cách đó bằng phương pháp sau .


1

Tôi nghĩ rằng tôi hiểu tại sao bạn hơi bối rối về sự gián đoạn. Vui lòng xem xét câu trả lời của tôi trong dòng:

Nếu tôi không bao giờ tự mình làm gián đoạn các chuỗi khác, điều gì có thể kích hoạt Ngoại lệ bị gián đoạn ?

Trước hết bạn có thể làm gián đoạn các chủ đề khác; Tôi biết rằng trong JCiP có đề cập rằng bạn không bao giờ được ngắt các luồng bạn không sở hữu; tuy nhiên, tuyên bố này phải được hiểu đúng. Điều đó có nghĩa là mã của bạn có thể đang chạy trong bất kỳ chuỗi tùy ý nào sẽ không xử lý gián đoạn bởi vì nó không phải là chủ sở hữu của chuỗi đó nên không có manh mối nào về chính sách ngắt của nó. Vì vậy, bạn có thể yêu cầu gián đoạn trên các chuỗi khác, nhưng hãy để chủ sở hữu của nó thực hiện hành động gián đoạn; nó có chính sách gián đoạn được đóng gói trong nó, không phải mã tác vụ của bạn; ít nhất là lịch sự để đặt cờ gián đoạn!

Có nhiều cách giải thích tại sao vẫn có thể bị gián đoạn, có thể hết thời gian, gián đoạn JVM, v.v.

Nếu tôi chưa bao giờ tự mình làm gián đoạn các chuỗi khác bằng cách sử dụng ngắt () (giả sử vì tôi đang sử dụng các phương tiện khác để hủy các chuỗi đang hoạt động của mình, chẳng hạn như thuốc độc và vòng lặp kiểu while (! Đã hủy) [như cả hai đã giải thích trong JCIP]), thì sao Vậy thì InterruptException có nghĩa là gì? Tôi phải làm gì khi bắt được một con? Tắt ứng dụng của tôi?

Bạn cần phải rất cẩn thận ở đây; nếu bạn sở hữu luồng đã ném InterruptException (IE), thì bạn biết phải làm gì khi bắt được nó, chẳng hạn như bạn có thể tắt ứng dụng / dịch vụ của mình hoặc bạn có thể thay thế luồng bị chết này bằng một luồng mới! Tuy nhiên, nếu bạn không sở hữu luồng thì khi bắt được IE, hãy ném lại nó lên cao hơn trong ngăn xếp cuộc gọi hoặc sau khi làm gì đó (có thể đang ghi nhật ký), hãy đặt lại trạng thái bị gián đoạn để mã sở hữu luồng này, khi có quyền kiểm soát, có thể biết rằng luồng đã bị gián đoạn và do đó thực hiện các hành động như nó sẽ làm vì chỉ nó biết chính sách ngắt.

Hy vọng điều này sẽ giúp.


0

Câu InterruptedExceptionnói rằng một thói quen thể bị gián đoạn, nhưng không nhất thiết phải như vậy.

Nếu bạn không mong đợi sự gián đoạn thì bạn nên coi nó như bất kỳ trường hợp ngoại lệ bất ngờ nào khác. Nếu nó nằm trong phần quan trọng mà một ngoại lệ không mong muốn có thể gây ra hậu quả nghiêm trọng, tốt nhất có thể là thử dọn dẹp tài nguyên và tắt máy một cách duyên dáng (vì nhận được tín hiệu ngắt cho thấy ứng dụng được thiết kế tốt của bạn không dựa vào ngắt đang được sử dụng theo một cách nào đó nó không được thiết kế, và vì vậy chắc chắn có điều gì đó sai). Ngoài ra, nếu mã được đề cập là thứ gì đó không quan trọng hoặc tầm thường, bạn có thể muốn bỏ qua (hoặc ghi nhật ký) ngắt và tiếp tục.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.