Java Concurrency - นโยบายการหยุดชะงัก

Aug 26 2020

ฉันอ่านJava Concurrency ในการปฏิบัติ ในส่วนนโยบายการหยุดชะงักในบทที่

การยกเลิกและการปิดระบบ

กล่าวถึง

งานไม่ควรถือว่าอะไรเกี่ยวกับนโยบายการหยุดชะงักของเธรดการดำเนินการเว้นแต่จะได้รับการออกแบบอย่างชัดเจนให้ทำงานภายในบริการที่มีนโยบายการหยุดชะงัก ไม่ว่างานจะตีความการขัดจังหวะเป็นการยกเลิกหรือดำเนินการอื่น ๆ กับการหยุดชะงักก็ควรดูแลรักษาสถานะการหยุดชะงักของเธรดการดำเนินการ ถ้ามันไม่แพร่กระจาย InterruptedException ไปยังผู้เรียกมันควรเรียกคืนสถานะการหยุดชะงักหลังจากจับ InterruptionException: Thread.currentThread (). interrupt ()

ดังนั้นฉันจึงพยายามเล่นกับตัวอย่างรายชื่อเพื่อทำความเข้าใจ แต่ฉันสับสนกับผลลัพธ์

PrimeProducer

public class CorrectPrimeProducer extends Thread {

    private final BlockingQueue<BigInteger> queue;

    public CorrectPrimeProducer(BlockingQueue<BigInteger> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        try {
            System.out.println(Thread.currentThread().getName()+" interrupt status in producer:" + Thread.currentThread().isInterrupted());
            BigInteger p = BigInteger.ONE;
            while (!Thread.currentThread().isInterrupted()) {
                queue.put(p = p.nextProbablePrime());
            }
        } catch (InterruptedException e) {
            /* Allow thread to exit */
            Thread.currentThread().interrupt();
            System.out.println(Thread.currentThread().getName()+" interrupt status in producer catch:" + Thread.currentThread().isInterrupted());
        }
    }
}

วิธีการหลัก ##

public static void main(String[] args) throws InterruptedException {
        BlockingQueue<BigInteger> primes = new LinkedBlockingQueue<>();
        CorrectPrimeProducer generator = new CorrectPrimeProducer(primes);
        generator.start();
        try {
            while (needMorePrimes()) {
                consume(primes.take());
            }
        } finally {
            generator.interrupt();
        }
        TimeUnit.SECONDS.sleep(5);
        System.out.println(generator.getName()+" interrupt status in main:"+generator.isInterrupted());
    }

    //do something
    private static void consume(BigInteger take) {
        System.out.println(take);
    }

    private static int counter = 1;

    private static boolean needMorePrimes() {
        counter++;
        if(counter == 10){
// after counter reaches 10 return false
            return false;
        }
        return true; 
    }

เอาท์พุต:

// when TimeUnit.SECONDS.sleep(5); in main class is not commented

Thread-0 interrupt status in producer:false
2
3
5
7
11
13
17
19
Thread-0 interrupt status in producer catch:true
Thread-0 interrupt status in main:false
//When TimeUnit.SECONDS.sleep(5); in main class is commented
Thread-0 interrupt status in producer:false
2
3
5
7
11
13
17
19
Thread-0 interrupt status in main:true
Thread-0 interrupt status in producer catch:true

คำถาม

  1. เพียงแค่เพิ่ม TimeUnit.SECONDS.sleep (5) ในเธรดหลักในคลาสหลัก สถานะการขัดจังหวะเธรด (เช่นตัวสร้าง) กำลังได้รับการรีเซ็ต ถ้าฉันแสดงความคิดเห็นเมธอด TimeUnit.SECONDS.sleep (5) ในกรณีนั้นสถานะการขัดจังหวะจะยังคงอยู่ เหตุใดจึงเกิดขึ้นและเกิดขึ้นได้อย่างไร?

  2. ในหนังสือมีการกล่าวถึงเธรดควรถูกขัดจังหวะโดยเจ้าของเท่านั้น ในตัวอย่างข้างต้นใครเป็นเจ้าของ? ฉันคิดว่าเธรดวิธีหลักของมัน

คำตอบ

1 Joni Aug 26 2020 at 04:25

การเพิ่มTimeUnit.SECONDS.sleep(5)คุณกำลังให้เวลาเพียงพอสำหรับเธรดที่จะยุติ

เมื่อเธรดสิ้นสุดลงแฟล็กการขัดจังหวะจะถูกล้าง

สิ่งนี้ไม่ได้ระบุไว้ในข้อกำหนด แต่เป็นสิ่งที่เกิดขึ้น ดูตัวอย่างรายงานข้อบกพร่องนี้ :

ไม่มีการละเมิดข้อกำหนดใด ๆ ที่นี่ดังนั้นฉันจึงได้ส่งคำขอนี้เป็นการเพิ่มประสิทธิภาพแทนที่จะเป็นข้อบกพร่อง การขาดข้อกำหนดเป็นข้อบกพร่อง - เราตั้งใจระบุว่า "การขัดจังหวะหลังจากการยุติไม่จำเป็นต้องมีผลกระทบ" เพื่อจัดการกับข้อเท็จจริงที่ว่าสถานะการขัดจังหวะถูกเก็บไว้ใน VM และจะไม่มีอยู่อีกต่อไปเมื่อเธรดสิ้นสุดลง อย่างไรก็ตามเราละเลยที่จะสะท้อนให้เห็นว่าในข้อมูลจำเพาะ Thread.isInterrupted

หากไม่มีสิ่งพิเศษsleepฉันสงสัยว่าในทางทฤษฎีคุณสามารถเห็นทั้งสองสถานะtrueและfalseขัดจังหวะได้เนื่องจากมีสภาพการแข่งขัน แต่มีโอกาสมากที่คุณจะเห็นtrueเนื่องจากการตั้งเวลาเธรด หน้าต่างเวลาที่สถานะการขัดจังหวะเป็นเท็จระหว่างข้อยกเว้นที่ถูกโยนและสถานะการขัดจังหวะที่ถูกเรียกคืนในบล็อกการจับนั้นมีขนาดเล็กมากอย่างไม่น่าเชื่อ

2 michalk Aug 26 2020 at 03:49

เพียงแค่เพิ่ม TimeUnit.SECONDS.sleep (5) ในเธรดหลักในคลาสหลัก สถานะการขัดจังหวะเธรด (เช่นตัวสร้าง) กำลังได้รับการรีเซ็ต ถ้าฉันแสดงความคิดเห็นเมธอด TimeUnit.SECONDS.sleep (5) ในกรณีนั้นสถานะการขัดจังหวะจะยังคงอยู่ เหตุใดจึงเกิดขึ้นและเกิดขึ้นได้อย่างไร?

คุณไม่ได้ใช้กลไกการซิงโครไนซ์ใด ๆ (นอกเหนือจากการบล็อกคิว) ระหว่างเธรดหลักและCorrectPrimeProducerเมื่อเธรดหลักพิมพ์สถานะ - CorrectPrimeProducerอาจยังไม่ได้รักษาสถานะที่ถูกขัดจังหวะไว้ (โดยดำเนินการตามcatchคำแนะนำการบล็อก) ดังนั้นคุณจึงได้falseผลลัพธ์

เมื่อคุณเพิ่มลงsleepในเมนThreadคุณเพียงแค่เพิ่มความเป็นไปได้ที่CorrectPrimeProducerเธรดจะรักษาสถานะการหยุดชะงักโดยการเรียกใช้catchคำสั่งบล็อกก่อนที่เธรดหลักจะพยายามพิมพ์สถานะ trueนั่นคือเหตุผลที่มันพิมพ์

ในหนังสือมีการกล่าวถึงเธรดควรถูกขัดจังหวะโดยเจ้าของเท่านั้น ในตัวอย่างข้างต้นใครเป็นเจ้าของ? ฉันคิดว่าเธรดวิธีหลักของมัน

ในกรณีนี้คุณเป็นเจ้าของ (เจ้าของคือรหัสที่สร้างเธรด) ของCorrectPrimeProducerเธรดดังนั้นคุณจึงตัดสินใจว่าการหยุดชะงักหมายถึงอะไร ตัวอย่างเช่นคุณสามารถสร้างขึ้นใหม่ได้หากถูกขัดจังหวะ (สิ่งนี้เกิดขึ้นเช่นThreads จาก java thread pool โดยค่าเริ่มต้น)