鍍金池/ 問答/HTML5  Java/ 《Java并發(fā)編程實戰(zhàn)》一段代碼的疑惑

《Java并發(fā)編程實戰(zhàn)》一段代碼的疑惑

《Java并發(fā)編程實戰(zhàn)》3.1節(jié)的一段代碼:

public class NoVisibility {

    private static boolean ready;
    private static int number;
    
    private static class ReaderThread extends Thread {
        public void run() {
            while (!ready)
                Thread.yield();
            System.out.println(number);
        }
    }
    
    public static void main(String[] args) {
        new ReaderThread().start();
        number = 42;
        ready = true;
    }
}

按照書中所講,這段代碼不一定輸出42,有可能陷入死循環(huán)。原因是代碼中沒有足夠的同步機制,無法保證主線程寫入的ready他number對讀線程是可見的。也有可能是0,原因是“重排序”,讀線程看到了主線程寫入的ready卻沒有看到number。但是經過多次測試,始終輸出42,既沒有輸出0,也沒有死循環(huán)。為了驗證書中所說的主線程修改對讀線程不可見,我改寫了代碼:

public class NoVisibilityLoop {

    private static int number;
    
    private static class ReaderThread extends Thread {
        public void run() {
            while (true) {
                System.out.println(number);
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                }
            }
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        new ReaderThread().start();
        Thread.sleep(1000);
        number = 42;
    }
}

多次測試輸出結果是:
0
0
0
0
0
42
42
42
42
這個結果說明了主線程寫入的number對讀線程是可見的。但是這本書的作者一堆大牛,不會搞錯的。還請大家?guī)兔纯次业尿炞C方法哪里出問題了,謝謝。
運行環(huán)境:jdk 1.8.0_101,server模式。

回答
編輯回答
懶洋洋

http://www.cnblogs.com/dolphi...
建議看下這篇文章 講的很詳細 看完相信你能理解

2017年12月9日 03:29
編輯回答
情皺

原文的意思是讓你重復多次運行這段代碼
大概運行幾十次甚至上百次,可能出現(xiàn)一次死循環(huán),而這個在實際開發(fā)中是不可取的

而這是代碼設計缺陷的問題,所以建議不要這么編程,要保持主副線程的同步性不要用這樣的寫法,你繼續(xù)往后看,這書既然這么說,可能會有別的解決方案來幫你理解他描述的原理

2017年2月16日 20:31
編輯回答
落殤

應該是JDK版本差異造成的

2017年1月6日 11:08
編輯回答
貓館

首先測試多次正確也不能保證完全就是正確的,其次這本書是jdk5和6了,jdk8估計做了些優(yōu)化,

private static boolean ready;
private static int number;

private static class ReaderThread extends Thread {
    @Override
    public void run() {
        int i=0;
        while (!ready) {
            i++;
//                Thread.yield();
        }
        System.out.println(number);
    }
}

public static void main(String[] args) throws Exception {
    new ReaderThread().start();
    TimeUnit.MILLISECONDS .sleep(9);
    number = 42;
    ready = true;
}

把 thread.yield 換成 i++ 或者 sleep 與否 結果都有差別
這種執(zhí)行順序是指令重排決定的,不用volatile沒法保證

2018年1月13日 00:50