Multithreading - Soalan tentang keterlihatan memori Java
漂亮男人
漂亮男人 2017-05-17 10:06:58
0
4
969

Sila lihat kod berikut

public class TestVolatile {
    
    public static void main(String[] args) throws InterruptedException {
        ThreadDemo td = new ThreadDemo();
        new Thread(td).start();
        
        Thread.sleep(1);
        while(true){
            if(td.isFlag()){
                System.out.println("------------------");
                break;
            }
        }
        
    }

}

class ThreadDemo implements Runnable {

    private boolean flag = false;

    @Override
    public void run() {
        
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
        }

        flag = true;
        
        System.out.println("flag=" + isFlag());

    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

}

Letak Thread.sleep(1)换成Thread.sleep(1000)就能获取flag修改后的值,即td.isFlag()返回true.
Walaupun saya telah membaca konsep model memori Java, saya tidak tahu bagaimana untuk mentafsir kod ini Siapa yang boleh menerangkannya?

Soalan berkaitan: Apakah memori kerja Java multi-threading?

漂亮男人
漂亮男人

membalas semua(4)
淡淡烟草味

Anda perlu beritahu saya dahulu apakah kesan jangkaan anda? Tanya soalan dengan jelas

滿天的星座

Jangkaan ini tidak disokong oleh piawaian. Tiada apa-apa yang dilakukan dalam kod untuk menjamin bahawa "tulisan subthread berlaku-sebelum utas utama dibaca".

sleep(1000)Melihat pengubahsuaian kemudian hanyalah satu kebetulan Jika JVM menunggu lebih lama untuk utas utama untuk melihatnya, atau tidak pernah membiarkan utas utama melihatnya, ia tidak melanggar spesifikasi.

刘奇

Program anda sepatutnya ingin menguji kefungsian kata kunci volatile. Tetapi "menggantikan Thread.sleep(1) dengan Thread.sleep(1000) akan mencapai kesan yang diingini" bukanlah pemahaman yang betul.
Pertama sekali, terdapat dua utas dalam atur cara, utas utama (secara sementara dipanggil utas M) dan Benang baru(td) (sementara dipanggil utas T). volatile 关键字的功能。但是 “把 Thread.sleep(1) 换成 Thread.sleep(1000) 就能获得预期效果” 这样做理解上是不对的。
首先,程序中总共有两个线程,主线程(暂称 线程M)和 new Thread(td) (暂称 线程T)。


当写 Thread.sleep(1) 的时候,线程M 在 1ms 之后,便开始在 while(true) 循环中检查 td.isFlag() 的值,但是因为内存可见性的关系,线程M 并不能及时读取 线程T 中 flag 的值,所以此时导致了死循环;


当写 Thread.sleep(1000) 的时候,M 在 1000ms 之后,开始在 while(true) 循环中检查 td.isFlag() 的值;但是 T 在 200ms 的时候,便将 flag 的值设为 true 了,所以,M 在 1000ms 之后检测 td.isFlag() 的值肯定是返回 true 的,那么第一次判断便会返回 true,产生输出并跳出 while(true) 循环。


为了让 线程M 及时读取到 线程T 中 flag 的值,需要将 flag 使用 volatile 关键字进行修饰:

private volatile boolean flag = false;

那么每次对 flag 的修改,其他线程都立马可见。关于 volatile


Apabila menulis Thread.sleep(1), thread M mula menyemak td.isFlag() dalam gelung while(true) selepas 1ms , tetapi disebabkan keterlihatan memori, utas M tidak dapat membaca nilai bendera dalam utas T dalam masa, jadi gelung tak terhingga disebabkan pada masa ini 🎜
🎜Apabila menulis Thread.sleep(1000), M mula menyemak td.isFlag() dalam gelung while(true) selepas 1000ms. code>; tetapi T menetapkan nilai flag kepada true pada 200ms, jadi M mengesan td.isFlag( selepas 1000ms ) mesti mengembalikan benar, maka penghakiman pertama akan mengembalikan true, menjana output dan melompat keluar daripada gelung while(true) code>. 🎜
🎜Untuk thread M membaca nilai flag dalam thread T dalam masa, flag perlu diubah suai dengan kata kunci volatile: 🎜 rrreee 🎜Kemudian setiap pengubahsuaian bendera akan kelihatan serta-merta kepada urutan lain. Mengenai penggunaan volatile, anda boleh rujuk blog saya: Java Multithreading (6): Penggunaan kata kunci yang tidak menentu 🎜
大家讲道理

Anda boleh merujuk kepada tiga kod berikut:
Kod pertama adalah sama dengan situasi anda disebabkan masalah keterlihatan berbilang benang, ia mungkin menyebabkan gelung yang tidak terhingga.
Yang kedua ialah menggunakan disegerakkan untuk menyelesaikan masalah ini. Ini bagus untuk kebanyakan senario kerja synchronized解决此问题,大多数工作场景用这个好
第三个是使用volatileYang ketiga ialah menggunakan volatile untuk menyelesaikan masalah ini, tetapi kata kunci ini sahaja menjamin keterlihatan Dalam senario sebenar, hadnya agak besar, jadi gunakannya dengan berhati-hati

public class StopThread {
    
    private static boolean stopRequested;
    
    public static void main(String[] args) throws InterruptedException {
        Thread backgroundThread = new Thread(new Runnable() {
            
            @Override
            public void run() {
                @SuppressWarnings("unused")
                int i = 0;
                while(!stopRequested) {
//                    System.out.println("加上这一句程序就可以终止,否则无限循环下去");
                    i++;
                }
            }
        });
        
        backgroundThread.start();
        TimeUnit.SECONDS.sleep(1);
        stopRequested = true;
    }
}
public class StopThread2 {
    
    private static boolean stopRequested;
    
    public static synchronized boolean getStopRequested() {
        return stopRequested;
    }
    
    public static synchronized void requestStop() {
        stopRequested = true;
    }
    
    public static void main(String[] args) throws InterruptedException {
        Thread backgroundThread = new Thread(new Runnable() {
            
            @Override
            public void run() {
                @SuppressWarnings("unused")
                int i = 0;
                while(!getStopRequested()/* stopRequested */) {
                    i++;
                }
            }
        });
        
        backgroundThread.start();
        TimeUnit.SECONDS.sleep(1);
        requestStop();/* stopRequested = true; */
    }
}
public class StopThread3 {
    
    private static volatile boolean stopRequested;
    
    
    public static void main(String[] args) throws InterruptedException {
        Thread backgroundThread = new Thread(new Runnable() {
            
            @Override
            public void run() {
                @SuppressWarnings("unused")
                int i = 0;
                while(stopRequested) {
                    i++;
                }
            }
        });
        
        backgroundThread.start();
        TimeUnit.SECONDS.sleep(1);
        stopRequested = true;
    }
}
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan