volatile保证可见性的验证

一、前言

    java内存模型中的可见性是指,当一个线程修改了共享变量的值后,其他线程可以立马知道这个修改后的值。在《Java并发编程:volatile关键字解析》中有这么一段话:

  对于可见性,Java提供了volatile关键字来保证可见性。

  当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。

  而普通的共享变量不能保证可见性,因为普通共享变量被修改之后,什么时候被写入主存是不确定的,当其他线程去读取时,此时内存中可能还是原来的旧值,因此无法保证可见性。

    对于这一论点,网上鲜有论据。所以,笔者通过几个简单的例子来证明volatile确实可以保证可见性。

二、论证过程

    每个线程都有一个工作内存,线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。不同线程之间也无法直接访问对方工作内存中的变量,线程间变量的传递依靠主内存来完成。
在这里插入图片描述
    以此原理,设计了如下的例子:

package ThreadPool;

public class VolatileTest {
    public boolean isShutdown;

    public boolean getShutdown () {
        return isShutdown;
    }

    public void shutdown () {
        isShutdown = true;
    }

    public class ReaderThread extends Thread {
        @Override
        public void run() {
            try {
                System.out.println("开始循环");
                while (!isShutdown) {

                };
                System.out.println("结束循环");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    public class WatchThread extends Thread {
        @Override
        public void run() {
            shutdown();
        }
    }
    
    public static void main(String[] args){
        try {
            VolatileTest volatileTest = new VolatileTest();
            volatileTest.new ReaderThread().start();
            //让主线程睡眠一秒,确保另一个线程调用shutdown方法时死循环已经开始
            Thread.sleep(1000);

            volatileTest.new WatchThread().start();
            //此刻的睡眠是为了确保shutdown方法对isShutdown变量的修改已经同步到主内存
            Thread.sleep(1000);
            //打印isShutdown的值
            System.out.println("getShutdown:" + volatileTest.getShutdown());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

    isShutdown是共享变量,默认值是false。ReaderThread线程的执行体是一个死循环,直到isShutdown变为true才跳出循环,打印“结束循环”。WatchThread线程的执行体调用了shutdown方法,将isShutdown的值改为true。如果说ReaderThread线程跳出了死循环,那么就说明WatchThread线程对isShutdown的修改是对其可见的,反之,则不可见。
    运行结果如下:
在这里插入图片描述
    由此可见,WatchThread对isShutdown变量的修改是生效的,但ReaderThread并没有跳出循环,也就意味着ReaderThread并没有读取到isShutdown变量的最新值,而是读取工作内存中的旧值。所以,普通变量是不具有可见性的。
    紧接着,我们用volatile去修饰isShutdown变量。
在这里插入图片描述
    运行结果如下:
在这里插入图片描述
    这一次,ReaderThread跳出了死循环,打印出了“结束循环”,这说明ReaderThread可以读取到isShutdown变量的最新值,换句话说就是,WatchThread对isShutdown变量的修改对于ReaderThread是可见的。

三、总结

    综上所述,volatile确实可以保证可见性。

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值