เหตุใดจึงเรียกใช้ Thread.currentThread.interrupt () ใน catch InterruptException block


คำตอบ:


160

นี้จะทำเพื่อให้รัฐ

เมื่อคุณจับInterruptExceptionและกลืนคุณจะต้องป้องกันวิธีการ / กลุ่มเธรดในระดับที่สูงขึ้นจากการสังเกตเห็นการขัดจังหวะ ซึ่งอาจทำให้เกิดปัญหา

โดยการโทร Thread.currentThread().interrupt()คุณตั้งค่าสถานะอินเตอร์รัปต์ของเธรดดังนั้นตัวจัดการอินเตอร์รัปต์ระดับที่สูงกว่าจะสังเกตเห็นและสามารถจัดการได้อย่างเหมาะสม

Java Concurrency ในการปฏิบัติกล่าวถึงในรายละเอียดในบทที่ 7.1.3: การตอบสนองต่อการหยุดชะงัก กฎของมันคือ:

รหัสเท่านั้นที่ใช้นโยบายการขัดจังหวะของเธรดอาจกลืนคำขอการขัดจังหวะ งานเอนกประสงค์และรหัสห้องสมุดไม่ควรกลืนคำขอขัดจังหวะ


15
ในเอกสารระบุว่า"โดยการประชุมวิธีการใด ๆ ที่ออกโดยการโยนInterruptedException สถานะขัดจังหวะที่ชัดเจนเมื่อทำเช่นนั้นฉันคิดว่านี่จะทำให้คำตอบชัดเจนขึ้นในแง่ของสาเหตุที่คุณต้องรักษาสถานะการขัดจังหวะ
Stelios Adamantidis

นอกจากนี้ยังเป็นที่น่าสังเกตว่าการinterrupt()โทรเป็นวิธีเดียวในการตั้งค่าสถานะที่ถูกขัดจังหวะเมื่อคุณได้รับการแจ้งเตือนเกี่ยวกับสถานะนี้ผ่าน "กลไกการจัดส่ง" อื่น ๆ - InterruptedExceptionและต้องการหรือไม่สามารถโยนทิ้งได้
sevo

67

ฉันคิดว่าตัวอย่างโค้ดนี้ทำให้สิ่งต่าง ๆ ชัดเจน ชั้นเรียนซึ่งทำงาน:

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

ชั้นหลัก:

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

    }

ลองโทรขัดจังหวะโดยไม่ตั้งสถานะกลับ


13
ดังนั้นข้อสรุปคืออะไร?
สกอตต์混合理论

3
ขอบคุณ ฉันเห็นสิ่งที่คุณหมายถึงตอนนี้: repl.it/@djangofan/InterruptedThreadExample
djangofan

20

บันทึก:

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

ฉันจะหยุดเธรดที่รอเป็นเวลานานได้อย่างไร (เช่นสำหรับอินพุต)

เพื่อให้เทคนิคนี้ใช้งานได้เป็นสิ่งสำคัญที่วิธีการใดก็ตามที่จับข้อยกเว้นขัดจังหวะและไม่ได้เตรียมที่จะจัดการกับข้อยกเว้นนั้นทันที เราพูดว่า reasserts มากกว่า rethrows เพราะมันเป็นไปไม่ได้เสมอที่จะทำการยกเว้นใหม่ หากวิธีการที่จับ InterruptException ไม่ได้ประกาศว่าจะโยนข้อยกเว้น (ตรวจสอบ) นี้ก็ควร "reinterrupt ตัวเอง" ด้วยคาถาต่อไปนี้:

Thread.currentThread().interrupt();

สิ่งนี้ช่วยให้มั่นใจได้ว่าเธรดจะทำการ InterruptException ทันทีที่สามารถทำได้


2

ฉันคิดว่ามันเป็นการปฏิบัติที่ไม่ดีหรืออย่างน้อยก็มีความเสี่ยง โดยปกติแล้ววิธีการระดับสูงกว่าจะไม่ทำการบล็อกและจะไม่เห็นInterruptedExceptionหยุด หากคุณปิดบังไว้ในทุกที่ที่คุณทำการดำเนินการขัดจังหวะคุณจะไม่ได้รับมัน

เหตุผลเดียวที่Thread.currentThread.interrupt()ทำให้ไม่ยกข้อยกเว้นอื่น ๆ หรือส่งสัญญาณคำขอขัดจังหวะด้วยวิธีอื่น ๆ (เช่นการตั้งค่าinterruptedตัวแปรตัวแปรท้องถิ่นในลูปหลักของเธรด) คือสถานการณ์ที่คุณไม่สามารถทำสิ่งใดด้วยข้อยกเว้นเช่นในfinallyบล็อก

ดูคำตอบของPéterTörökหากคุณต้องการเข้าใจความหมายของการThread.currentThread.interrupt()โทร


0

อ้างอิงจาก java doc

หากเธรดนี้ถูกบล็อกในการเรียกใช้การรอ (), เข้าร่วม (), สลีป (ยาว) จากนั้นสถานะการขัดจังหวะของมันจะถูกล้างและจะได้รับการขัดจังหวะ

ถ้าเธรดนี้ถูกบล็อกในการดำเนินการ I / O สถานะการขัดจังหวะของเธรดจะถูกตั้งค่าและเธรดจะได้รับ ClosedByInterruptException

หากเธรดนี้ถูกบล็อกในตัวเลือกสถานะการขัดจังหวะของเธรดจะถูกตั้งค่าและมันจะกลับมาทันทีจากการดำเนินการเลือก

หากไม่มีเงื่อนไขก่อนหน้านี้ค้างไว้สถานะขัดจังหวะของเธรดนี้จะถูกตั้งค่า

ดังนั้นหากคุณเปลี่ยนวิธี sleepBabySleep () ในการดำเนินการ @Ajay George Answer to I / O หรือเพียงแค่ sysout คุณไม่จำเป็นต้องตั้งสถานะกลับเพื่อหยุดโปรแกรม (BTW พวกเขาไม่ได้โยนการขัดจังหวะด้วยข้อยกเว้น)

เช่นเดียวกับ @ PéterTörökพูดว่า => สิ่งนี้ทำเพื่อรักษาสถานะ (และโดยเฉพาะอย่างยิ่งสำหรับวิธีการที่จะทำให้เกิดการขัดจังหวะยกเว้น)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.