关于Java内存可见性的问题
澳门新葡京官网
澳门新葡京官网
当前位置 : 澳门新葡京官网 > 新葡京娱乐场

关于Java内存可见性的问题

请看以下代码

public class TestVolatile {
    
    public static void mainString[] args throws InterruptedException {
        ThreadDemo td = new ThreadDemo;
        new Threadtd.start;
        
        Thread.sleep1;
        whiletrue{
            iftd.isFlag{
                System.out.println"------------------";
                break;
            }
        }
        
    }

}

class ThreadDemo implements Runnable {

    private boolean flag = false;

    @Override
    public void run {
        
        try {
            Thread.sleep200;
        } catch InterruptedException e {
        }

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

    }

    public boolean isFlag {
        return flag;
    }

    public void setFlagboolean flag {
        this.flag = flag;
    }

}

Thread.sleep1换成Thread.sleep1000就能获取flag修改后的值,即td.isFlag返回true
虽然看了Java内存模型的概念,但我不知道如何解释这段代码,谁能解释一下?

相关问题: Java多线程的工作内存是什么?

你得先说说你的预期效果是啥?问问题要问清楚啊

这个期待是没有规范支撑的。代码中没有做任何能保证 "子线程写 happen-before 主线程读" 的事情。

sleep1000后看到修改只是巧合,一个JVM如果在更久后才让主线程看到,甚至永远不让主线程看到都不违反规范。

你的程序应该是想测试 volatile 关键字的功能。但是 “把 Thread.sleep1 换成 Thread.sleep1000 就能获得预期效果” 这样做理解上是不对的。
首先,程序中总共有两个线程,主线程(暂称 线程M)和 new Threadtd (暂称 线程T)。


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


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


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

private volatile boolean flag = false;

那么每次对 flag 的修改,其他线程都立马可见。关于 volatile 的使用,可以参考我的博客:Java 多线程(6):volatile 关键字的使用

可以参考如下三个代码:
其中第一个和你的情况一样,由于多线程的可见性问题,可能导致无限循环下去。
第二个是使用synchronized解决此问题,大多数工作场景用这个好
第三个是使用volatile解决,但这个关键字只保证可见性,在实际场景中局限性比较大,得慎用

public class StopThread {
    
    private static boolean stopRequested;
    
    public static void mainString[] args throws InterruptedException {
        Thread backgroundThread = new Threadnew Runnable {
            
            @Override
            public void run {
                @SuppressWarnings"unused"
                int i = 0;
                while!stopRequested {
//                    System.out.println"加上这一句程序就可以终止,否则无限循环下去";
                    i++;
                }
            }
        };
        
        backgroundThread.start;
        TimeUnit.SECONDS.sleep1;
        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 mainString[] args throws InterruptedException {
        Thread backgroundThread = new Threadnew Runnable {
            
            @Override
            public void run {
                @SuppressWarnings"unused"
                int i = 0;
                while!getStopRequested/* stopRequested */ {
                    i++;
                }
            }
        };
        
        backgroundThread.start;
        TimeUnit.SECONDS.sleep1;
        requestStop;/* stopRequested = true; */
    }
}
public class StopThread3 {
    
    private static volatile boolean stopRequested;
    
    
    public static void mainString[] args throws InterruptedException {
        Thread backgroundThread = new Threadnew Runnable {
            
            @Override
            public void run {
                @SuppressWarnings"unused"
                int i = 0;
                whilestopRequested {
                    i++;
                }
            }
        };
        
        backgroundThread.start;
        TimeUnit.SECONDS.sleep1;
        stopRequested = true;
    }
}

栏目列表

广告位

澳门新葡京官网