Home  >  Q&A  >  body text

Multithreading - Question about Java memory visibility

Please see the following code

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

}

Replace Thread.sleep(1) with Thread.sleep(1000) to get the modified value of flag, which is td .isFlag()returnstrue.
Although I have read the concept of Java memory model, I don't know how to explain this code. Who can explain it?

Related questions: What is the working memory of Java multi-threading?

漂亮男人漂亮男人2690 days ago892

reply all(4)I'll reply

  • 淡淡烟草味

    淡淡烟草味2017-05-17 10:08:58

    You need to first tell me what your expected effect is? Ask questions clearly

    reply
    0
  • 滿天的星座

    滿天的星座2017-05-17 10:08:58

    This expectation is not supported by standards. Nothing is done in the code to guarantee that "subthread writes happen-before main thread reads".

    sleep(1000)Seeing the modification later is just a coincidence. If a JVM waits longer for the main thread to see it, or even never lets the main thread see it, it does not violate the specification.

    reply
    0
  • 怪我咯

    怪我咯2017-05-17 10:08:58

    Your program should be tested volatile 关键字的功能。但是 “把 Thread.sleep(1) 换成 Thread.sleep(1000) 就能获得预期效果” 这样做理解上是不对的。
    首先,程序中总共有两个线程,主线程(暂称 线程M)和 new Thread(td) (tentatively called thread T).


    When writing the value of Thread.sleep(1) 的时候,线程M 在 1ms 之后,便开始在 while(true) 循环中检查 td.isFlag(), due to memory visibility, thread M cannot read the value of flag in thread T in time, so an infinite loop is caused at this time;


    When writing Thread.sleep(1000), M starts to check td.isFlag() in the while(true) loop after 1000ms. code>; but T sets the value of Thread.sleep(1000) 的时候,M 在 1000ms 之后,开始在 while(true) 循环中检查 td.isFlag() 的值;但是 T 在 200ms 的时候,便将 flag 的值设为 true 了,所以,M 在 1000ms 之后检测 td.isFlag() 的值肯定是返回 true 的,那么第一次判断便会返回 true,产生输出并跳出 while(true)flag

    to true at 200ms, so M detects td.isFlag() after 1000ms The value must return true, then the first judgment will return true, generate output and jump out of the while(true) loop.

    In order for thread M to read the value of flag in thread T in time, flagvolatile needs to be modified with the

    keyword:

    private volatile boolean flag = false;
    Then every modification to flagvolatile will be immediately visible to other threads. Regarding the use of

    , you can refer to my blog: Java Multithreading (6): Use of volatile keyword 🎜

    reply
    0
  • 大家讲道理

    大家讲道理2017-05-17 10:08:58

    You can refer to the following three codes:
    The first one is the same as your situation. Due to the visibility problem of multi-threading, it may cause an infinite loop.
    The second is to use synchronized to solve this problem. This is good for most work scenarios. synchronized解决此问题,大多数工作场景用这个好
    第三个是使用volatileThe third is to use volatile to solve this problem, but this keyword only guarantees visibility. In actual scenarios, the limitations are relatively large, so use it with caution

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

    reply
    0
  • Cancelreply