Java Concurrency - Kebijakan Interupsi

Aug 26 2020

Saya membaca Java Concurrency in Practice . Di bagian Kebijakan Interupsi di bab

Pembatalan dan Shutdown

Ini disebutkan

Tugas tidak boleh mengasumsikan apa pun tentang kebijakan interupsi dari utas pelaksananya kecuali jika dirancang secara eksplisit untuk dijalankan dalam layanan yang memiliki kebijakan interupsi tertentu. Apakah tugas menafsirkan interupsi sebagai pembatalan atau mengambil tindakan lain terhadap interupsi, tugas tersebut harus berhati-hati untuk mempertahankan status interupsi thread yang menjalankan. Jika tidak akan menyebarkan InterruptedException ke pemanggilnya, ia harus memulihkan status interupsi setelah menangkap InterruptionException: Thread.currentThread (). Interrupt ()

Jadi saya mencoba bermain-main dengan daftar sampel untuk memahami. Tapi saya bingung dengan hasilnya.

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

metode utama ##

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

Keluaran:

// 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

Pertanyaan

  1. Hanya dengan menambahkan TimeUnit.SECONDS.sleep (5) di utas utama di kelas utama. Status interupsi thread yang sedang dijalankan (mis., Generator) sedang disetel ulang. Jika saya mengomentari metode TimeUnit.SECONDS.sleep (5) maka dalam hal ini status interupsi dipertahankan. Mengapa ini terjadi dan bagaimana caranya?

  2. Dalam buku disebutkan Sebuah utas harus diinterupsi hanya oleh pemiliknya. Di sini, di contoh di atas, siapakah pemiliknya? Saya pikir utas metode utamanya.

Jawaban

1 Joni Aug 26 2020 at 04:25

Dengan menambahkan TimeUnit.SECONDS.sleep(5)Anda memberikan cukup waktu untuk mengakhiri utas.

Saat utas berakhir, bendera interupsinya dihapus.

Ini tidak didokumentasikan dalam spesifikasi, tetapi itulah yang terjadi. Lihat misalnya laporan bug ini :

Tidak ada spesifikasi yang dilanggar di sini jadi saya telah membuat ini permintaan peningkatan daripada bug. Bisa dibilang kurangnya spesifikasi adalah bug - kami sengaja menetapkan bahwa "interupsi setelah penghentian tidak berpengaruh" untuk menangani fakta bahwa status interupsi disimpan di VM dan tidak lagi ada setelah thread dihentikan. Namun kami mengabaikan untuk merefleksikannya di spesifikasi Thread.isInterrupted.

Tanpa tambahan sleep, saya menduga bahwa secara teori Anda dapat melihat keduanya truedan falsestatus interupsi karena ada kondisi balapan, tetapi kemungkinan besar Anda akan melihat trueberkat penjadwalan utas. Jendela waktu di mana status interupsi salah, antara pengecualian yang dilemparkan dan status interupsi dipulihkan di blok tangkap, sangat kecil.

2 michalk Aug 26 2020 at 03:49

Hanya dengan menambahkan TimeUnit.SECONDS.sleep (5) di utas utama di kelas utama. Status interupsi thread yang sedang dijalankan (mis., Generator) sedang disetel ulang. Jika saya mengomentari metode TimeUnit.SECONDS.sleep (5) maka dalam hal ini status interupsi dipertahankan. Mengapa ini terjadi dan bagaimana caranya?

Anda tidak menggunakan mekanisme sinkronisasi apa pun (selain memblokir antrian) antara utas utama dan CorrectPrimeProducerjadi ketika utas utama mencetak status - CorrectPrimeProducermungkin belum mempertahankan status terputus (dengan melakukan catchinstruksi blok) sehingga Anda mendapatkan falsehasilnya.

Saat Anda menambahkan sleepke utama, ThreadAnda hanya meningkatkan kemungkinan bahwa CorrectPrimeProducerutas mempertahankan status interupsi dengan menjalankan catchinstruksi blok sebelum utas utama mencoba mencetak statusnya. Itulah mengapa dicetak true.

Dalam buku disebutkan Sebuah utas harus diinterupsi hanya oleh pemiliknya. Di sini, di contoh di atas, siapakah pemiliknya? Saya pikir utas metode utamanya.

Dalam hal ini Anda adalah pemilik (pemilik adalah kode yang membuat utas) CorrectPrimeProducerutas sehingga Anda memutuskan apa artinya interupsi. Misalnya Anda dapat membuatnya kembali jika terputus (ini terjadi misalnya untuk Threads dari kumpulan utas java secara default).