Câu hỏi Ai đang gọi phương thức ngắt Java () nếu tôi không?


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

  1. Nếu tôi không bao giờ tự làm gián đoạn các chủ đề khác, điều gì có thể kích hoạt InterruptedException?

  2. Nếu tôi không bao giờ tự làm gián đoạn các chủ đề khác bằng làm gián đoạn() (nói bởi vì tôi đang sử dụng các phương tiện khác để hủy bỏ các chủ đề làm việc của tôi, như thuốc độc và trong khi (! bị hủy) kiểu vòng lặp [như được giải thích trong JCIP]), cái gì InterruptedException sau đó có nghĩa là gì? Tôi phải làm gì khi bắt một cái? Tắt ứng dụng của tôi?


76
2018-01-24 12:25


gốc




Các câu trả lời:


Cơ chế ngắt luồng là cách ưu tiên để có được một luồng (hợp tác) để đáp ứng một yêu cầu để ngăn chặn nó đang làm gì. Bất kỳ chủ đề nào (bao gồm cả chính chuỗi 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 cho interrupt() liên quan đến một số loại khung hoặc người quản lý nói với một số chuỗi công nhân để ngăn chặn những gì họ đang làm. Nếu chuỗi công nhân là "gián đoạn nhận thức", 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ị gián đoạn của nó. Khi nhận thấy rằng nó đã bị gián đoạn, một chuỗi được xử lý 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 một khung công tác Java hoặc từ một số chuỗi công nhân. 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ự nó kết thúc bằng các phương tiện 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ả lại hoặc bằng cách ném một số ngoại lệ thích hợp. Nhưng có lẽ không nên gọi System.exit(). (Ứng dụng của bạn không nhất thiết phải biết lý do tại sao nó bị gián đoạn, và nó chắc chắn không biết nếu có các chủ đề khác mà cần phải bị gián đoạn bởi khuôn khổ.)

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ố khung công tác, bạn có thể lập luận rằng InterruptedException là một ngoại lệ không mong muốn; tức là một lỗi. Trong trường hợp đó, bạn nên đối xử với ngoại lệ như bạn làm các lỗi khác; ví dụ. bọc nó trong một ngoại lệ không được kiểm soát, và nắm bắt và đăng nhập nó tại cùng một điểm bạn đối phó với các trường hợp ngoại lệ không được kiểm soát bất ngờ khác. (Ngoài ra, ứng dụng của bạn có thể đơn giản bỏ qua ngắt 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 ngắt lời các chủ đề khác, điều gì có thể kích hoạt một InterruptedException?

Một ví dụ là nếu Runnable các đối tượng được thực hiện bằng cách sử dụng một ExecutorService và shutdownNow() được gọi trên dịch vụ. Và về mặt lý thuyết, bất kỳ khung chủ đề hoặc khung quản lý luồng của bên thứ ba nào có thể làm một việc hợp pháp như thế này.

2) Nếu tôi không bao giờ bao giờ gián đoạn các chủ đề khác bản thân mình bằng cách sử dụng ngắt () ... những gì hiện một InterruptedExceptionsau đó có nghĩa là gì? Tôi phải làm gì khi bắt một cái? Tắt ứng dụng của tôi?

Bạn cần phân tích codebase để tìm ra điều gì đang tạo ra interrupt() cuộc gọi và lý do. Khi bạn đã tìm ra điều đó, bạn có thể tìm hiểu << phần ứng dụng của bạn cần làm gì.

Cho đến khi bạn biết tại sao InterruptedException đang bị ném, tôi sẽ khuyên điều trị nó như một lỗi cứng; ví dụ. in một 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 đưa đến sự chú ý của nhà phát triển / người duy trì.)

3) Làm thế nào để tôi biết ai đang gọi ai interrupt()?

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


44
2018-01-24 14:41



> Bất kỳ luồng nào có thể gọi ngắt () trên một Chủ đề - từ JCiP (Chính sách 7.1.2.Interruption): "Bởi vì mỗi chuỗi có chính sách gián đoạn riêng, bạn không nên ngắt một chủ đề trừ khi bạn biết những gì gián đoạn có nghĩa là chủ đề đó " - yetanothercoder
@yetanothercoderu - Yea ... well có thể không có nghĩa là Nên. Và mặt trái là đoạn mã làm bất ngờ InterruptedException (đó là cách mà nhiều lập trình viên "đối phó với" chúng) thậm chí còn bị phá vỡ nhiều hơn. - Stephen C
Tôi biết một câu hỏi cũ của nó, nhưng điều này vẫn không trả lời ai đang gọi là gián đoạn. Tôi có cùng một vấn đề, tôi gọi tắt máy () để chờ đợi cho các chủ đề để kết thúc, và nửa chừng tôi đang nhận được một gián đoạn từ một nơi nào đó: / - alianos-
@Andreas - hãy thử thiết lập một breakpoint trên Thread.interrupt ... - Stephen C
Ngoài ra, không có cách nào (hợp lý) nói chung để tìm ra thủ phạm. Cơ chế ngắt chuỗi Java không cung cấp bất kỳ cách nào để biết một gián đoạn đến từ đâu. - Stephen C


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() trên mã của bạn. ví dụ. nếu bạn quyết định trong tương lai để thực thi mã của bạn trong một ExecutorService, sau đó có thể buộc tắt máy qua interrupt().

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


12
2018-01-24 12:43



Tôi nghĩ rằng chỉ shutdownNow gọi phương thức ngắt (). Có đúng là tắt máy không? - Harinder


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

Tuy nhiên, bạn không nên điều trị InterruptedException một mình như là một "lệnh bỏ thuốc lá". Thay vào đó, bạn nên nghĩ rằng các ngắt là một phương tiện để kiểm soát trạng thái đang chạy của các luồng, nhiều theo cùng một cách như Object.notify() làm. Cũng giống như cách bạn kiểm tra trạng thái hiện tại sau khi thức dậy từ một cuộc gọi đến Object.wait() (bạn không cho rằng việc đánh thức có nghĩa là điều kiện chờ đợi của bạn đã được thỏa mãn), sau khi được đẩy vào với một ngắt, bạn nên kiểm tra 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.FutureTask có một isCancelled() phương pháp.

Mã mẫu:

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();
}

9
2017-10-12 08:38





Vấn đề với câu hỏi là "tôi". "Tôi" thường đề cập đến một trường hợp duy nhất của một lớp. Ý tôi là, rằng bất kỳ đoạn mã đặc biệt nào (lớp) không nên dựa vào việc triển khai toàn bộ hệ thống. Có 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).

Các ngắt bất ngờ có thể xảy ra từ JRE bị hủy các tác vụ trong java.util.concurrent và tắt các applet.

Xử lý ngắt luồng thường được viết không chính xác. Do đó, tôi đề nghị quyết định kiến ​​trúc để tránh gây 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 chính xác. Không thể ngắt kết nối khỏi nền tảng ngay bây giờ.


3
2018-01-24 16:39



Xin chào Tom, tôi nhớ tên của bạn từ c.l.j.p. ;) Vâng, chính xác: tôi không bao giờ phải ném làm gián đoạn() bản thân mình ... Trừ khi tôi bắt được một InterruptedException và cần phải khẳng định lại trạng thái bị gián đoạn nhưng điều này vẫn chưa rõ ràng với tôi. Tôi mới ở đây và ngạc nhiên bởi số lượng upvotes và câu trả lời / ý kiến ​​(cả những người đúng và những người sai): rõ ràng đó là một chủ đề đó không phải là tầm thường hoặc, ít nhất, thường không giải thích tốt. Điều đó nói rằng nhờ tất cả các bài viết tôi bắt đầu để có được một hình ảnh rõ ràng hơn về những gì đang xảy ra :) - SyntaxT3rr0r


Bạn có thể tìm hiểu điều này bằng cách tạo lớp chủ đề của riêng bạn (mở rộng java.lang.Thread) và ghi đè interrupt() phương pháp, trong đó bạn ghi lại stacktrace vào, nói, một trường String, và sau đó 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();
    }
}

2
2017-11-12 11:02





Như đã đề cập, một thư viện khác có thể làm gián đoạn luồng 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 chủ đề từ mã của bạn, chúng vẫn có thể nhận được danh sách các luồng đang chạy và ngắt chúng theo cách đó với phương pháp.


1
2018-01-24 18:10





Các InterruptedException nói rằng một thói quen có 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 gián đoạn thì bạn nên đối xử với nó như bạn có thể bất kỳ ngoại lệ bất ngờ khác. Nếu nó nằm trong một phần quan trọng mà một ngoại lệ không mong muốn có thể có hậu quả ghê gớm, có thể tốt nhất là thử và dọn dẹp tài nguyên và tắt máy một cách duyên dáng (bởi vì nhận được tín hiệu ngắt rằng ứng dụng được thiết kế tốt của bạn không phụ thuộc vào ngắt) theo cách nó không được thiết kế, và vì vậy phải có điều gì đó sai). Ngoài ra, nếu mã trong câu hỏi là một cái gì đó không quan trọng hoặc tầm thường, bạn có thể muốn bỏ qua (hoặc đăng nhập) các ngắt và tiếp tục đi.


0
2018-01-24 13:03