Tại sao gọi Thread.cienThread.interrupt () trong một khối InterruptException bắt?


Câu trả lời:


160

Điều này được thực hiện để giữ cho nhà nước .

Khi bạn bắt InterruptExceptionvà nuốt nó, về cơ bản, bạn sẽ ngăn không cho bất kỳ phương thức / nhóm luồng cấp cao nào chú ý đến ngắt. Mà có thể gây ra vấn đề.

Bằng cách gọi Thread.currentThread().interrupt(), bạn đặt cờ ngắt của luồng, vì vậy trình xử lý ngắt cấp cao hơn sẽ nhận thấy nó và có thể xử lý nó một cách thích hợp.

Thực hành đồng thời Java thảo luận điều này chi tiết hơn trong Chương 7.1.3: Ứng phó với sự gián đoạn . Quy tắc của nó là:

Chỉ mã thực hiện chính sách gián đoạn của một luồng có thể nuốt một yêu cầu gián đoạn. Nhiệm vụ mục đích chung và mã thư viện không bao giờ nên nuốt các yêu cầu gián đoạn.


15
Trong tài liệu có ghi rằng "Theo quy ước, bất kỳ phương pháp nào thoát ra bằng cách ném InterruptedException trạng thái ngắt rõ ràng khi thực hiện. Tôi nghĩ rằng điều này làm cho câu trả lời rõ ràng hơn về lý do tại sao bạn cần duy trì trạng thái ngắt.
Stelios Adamantidis

Cũng đáng lưu ý rằng interrupt()cuộc gọi là cách duy nhất để đặt cờ bị gián đoạn khi bạn nhận được thông báo về trạng thái này thông qua "cơ chế phân phối" khác - InterruptedExceptionvà muốn hoặc không thể ném lại.
sevo

67

Tôi nghĩ rằng mẫu mã này làm cho mọi thứ một chút rõ ràng. Lớp học thực hiện công việc:

   public class InterruptedSleepingThread extends Thread {

        @Override
        public void run() {
            doAPseudoHeavyWeightJob();
        }

        private void doAPseudoHeavyWeightJob() {
            for (int i=0;i<Integer.MAX_VALUE;i++) {
                //You are kidding me
                System.out.println(i + " " + i*2);
                //Let me sleep <evil grin>
                if(Thread.currentThread().isInterrupted()) {
                    System.out.println("Thread interrupted\n Exiting...");
                    break;
                }else {
                    sleepBabySleep();
                }
            }
        }

        /**
         *
         */
        protected void sleepBabySleep() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                //e.printStackTrace();
                Thread.currentThread().interrupt();
            }
        }
    }

Lớp chính:

   public class InterruptedSleepingThreadMain {

        /**
         * @param args
         * @throws InterruptedException
         */
        public static void main(String[] args) throws InterruptedException {
            InterruptedSleepingThread thread = new InterruptedSleepingThread();
            thread.start();
            //Giving 10 seconds to finish the job.
            Thread.sleep(10000);
            //Let me interrupt
            thread.interrupt();
        }

    }

Hãy thử ngắt cuộc gọi mà không đặt lại trạng thái.


13
vậy kết luận là ??
Scott 混合

3
Cảm ơn. Tôi xem những gì bạn có nghĩa là bây giờ: repl.it/@djangofan/InterruptedThreadExample
djangofan

20

Ghi chú:

http://doad.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

Làm cách nào để dừng một chuỗi chờ trong thời gian dài (ví dụ: cho đầu vào)?

Để kỹ thuật này hoạt động, điều quan trọng là bất kỳ phương pháp nào bắt được ngoại lệ ngắt và không được chuẩn bị để xử lý ngay lập tức sẽ xác nhận lại ngoại lệ đó. Chúng tôi nói rằng tái khẳng định hơn là rút lại, bởi vì không phải lúc nào cũng có thể lấy lại ngoại lệ. Nếu phương thức bắt InterruptedException không được khai báo để ném ngoại lệ (đã kiểm tra) này, thì nó sẽ "tự gián đoạn lại" với câu thần chú sau:

Thread.currentThread().interrupt();

Điều này đảm bảo rằng Thread sẽ phục hồi InterruptedException ngay khi có thể.


2

Tôi sẽ coi đó là một thực hành xấu hoặc ít nhất là một chút rủi ro. Thông thường các phương thức cấp cao hơn không thực hiện các hoạt động chặn và chúng sẽ không bao giờ nhìn thấyInterruptedException ở đó. Nếu bạn che giấu nó ở mọi nơi bạn thực hiện thao tác gián đoạn, bạn sẽ không bao giờ có được nó.

Lý do duy nhất cho Thread.currentThread.interrupt()và không đưa ra bất kỳ ngoại lệ hoặc yêu cầu ngắt tín hiệu nào theo bất kỳ cách nào khác (ví dụ: đặt interruptedbiến biến cục bộ trong vòng lặp chính của luồng) là tình huống mà bạn thực sự không thể làm gì với ngoại lệ, như trong các finallykhối.

Xem câu trả lời của Péter Török, nếu bạn muốn hiểu rõ hơn về hàm ý của Thread.currentThread.interrupt()cuộc gọi.


0

Tham khảo từ tài liệu java

Nếu chuỗi này bị chặn trong một lệnh gọi Wait (), tham gia (), ngủ (dài), thì trạng thái ngắt của nó sẽ bị xóa và nó sẽ nhận được InterruptedException.

Nếu luồng này bị chặn trong thao tác I / O, trạng thái ngắt của luồng sẽ được đặt và luồng sẽ nhận được một ĐóngByInterruptException.

Nếu luồng này bị chặn trong Bộ chọn thì trạng thái ngắt của luồng sẽ được đặt và nó sẽ trở lại ngay lập tức từ thao tác chọn.

Nếu không có điều kiện nào trước đó giữ thì trạng thái ngắt của luồng này sẽ được đặt.

Vì vậy, nếu bạn thay đổi phương thức ngủBabyS ngủ () trong @Ajay George Trả lời thao tác I / O hoặc chỉ một sysout, bạn không phải đặt lại trạng thái để dừng chương trình. (BTW, họ thậm chí không ném Interrupttedception)

Giống như @ Péter Török đã nói => Điều này được thực hiện để giữ trạng thái. (Và đặc biệt đối với phương thức sẽ ném Interrupttedception)

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.