Multithreading - Question sur la visibilité de la mémoire en Java
漂亮男人
漂亮男人 2017-05-17 10:06:58
0
4
928

Veuillez consulter le code suivant

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

}

Mettez Thread.sleep(1)换成Thread.sleep(1000)就能获取flag修改后的值,即td.isFlag()返回true.
Bien que j'ai lu le concept de modèle de mémoire Java, je ne sais pas comment interpréter ce code Qui peut l'expliquer ?

Question connexe : quelle est la mémoire de travail du multi-threading Java ?

漂亮男人
漂亮男人

répondre à tous(4)
淡淡烟草味

Vous devez d'abord me dire quel est votre effet attendu ? Posez des questions clairement

滿天的星座

Cette attente n’est pas prise en charge par les normes. Rien n'est fait dans le code pour garantir que "les écritures du sous-thread se produisent avant la lecture du thread principal".

sleep(1000)Voir la modification plus tard n'est qu'une coïncidence. Si une JVM attend plus longtemps que le thread principal la voie, ou même ne laisse jamais le thread principal la voir, elle ne viole pas la spécification.

刘奇

Votre programme devrait vouloir tester la fonctionnalité du mot-clé volatile. Mais "remplacer Thread.sleep(1) par Thread.sleep(1000) obtiendra l'effet souhaité" n'est pas une compréhension correcte.
Tout d'abord, il y a deux threads dans le programme, le thread principal (appelé provisoirement thread M) et le new Thread(td) (appelé provisoirement thread 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


Lors de l'écriture de Thread.sleep(1), le thread M commence à vérifier td.isFlag() dans la boucle while(true) après 1 ms , mais en raison de la visibilité de la mémoire, le thread M ne peut pas lire la valeur du flag dans le thread T à temps, donc une boucle infinie est provoquée à ce moment 🎜 ;
🎜Lors de l'écriture de Thread.sleep(1000), M commence à vérifier td.isFlag() dans la boucle while(true) après 1000 ms de code >; mais T définit la valeur de flag sur true à 200 ms, donc M détecte td.isFlag( après 1000 ms) doit renvoyer true, alors le premier jugement renverra true, générera une sortie et sortira de la boucle while(true) code>. 🎜
🎜Pour que le thread M puisse lire la valeur de flag dans le thread T à temps, flag doit être modifié avec le mot-clé volatile : 🎜 rrreee 🎜Ensuite, chaque modification apportée au flag sera immédiatement visible par les autres discussions. Concernant l'utilisation de volatile, vous pouvez vous référer à mon blog : Java Multithreading (6) : Utilisation du mot clé volatile 🎜
大家讲道理

Vous pouvez vous référer aux trois codes suivants :
Le premier est le même que votre situation En raison du problème de visibilité du multi-thread, cela peut provoquer une boucle infinie.
La deuxième consiste à utiliser synchronized pour résoudre ce problème. synchronized解决此问题,大多数工作场景用这个好
第三个是使用volatileLa troisième consiste à utiliser volatile pour résoudre ce problème, mais ce mot-clé uniquement. garantit la visibilité. Dans les scénarios réels, les limitations sont relativement importantes, alors utilisez-le avec prudence

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;
    }
}
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal