小白也能看懂的volatile关键字和JMM模型

通俗易懂的volatile关键字的探究

一、问题描述

首先大家来看一段非常简单且有意思的代码

package com.JMM;

import java.util.concurrent.TimeUnit;

/**
 * @author xsl
 */
class TestDate
{
     int num = 0;
}
public class JMM
{
    public static void main(String[] args)
    {
        TestDate testDate = new TestDate();
        System.out.println(testDate.num);
        new Thread(()-> {
            try
            {
                TimeUnit.SECONDS.sleep(3);
                testDate.num = 100;
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        },"a").start();
        while(testDate.num==0){
        }
    }
}

这段代码相信稍微懂一点Java线程的小伙伴都能看懂。首先我创建了一个TestDate类,这个类里面只有一个初始值为0的属性num。然后我在主线程中创建了一个对象testDate,打印了这个对象里面属性的值,然后马上创建了一个线程,让这个线程睡三秒,然后将这个对象属性的值改成100。然后外面有一个循环,一直在判断。最后你能想象出现了什么现象吗?
可能许多小伙伴和我当初一样认为,这不很简单吗,控制台首先输出一个0,然后停三秒,最后结束程序。结果现象和我想的完全不一样。
在这里插入图片描述
事实证明这个程序输出了一个0之后,它并没有结束程序,而是一直在循环,这说明num的值没有被修改,这是为什么呢?如果不相信的小伙伴可以自己运行这段代码去试试。

二、问题分析

这段看似简单的程序里面包含巨大的秘密,现在我们把这个程序改一下,将TestDate类里面的num属性用volatile关键字来修饰一下,结果竟然和刚刚的不一样了,这个程序输出0之后睡三秒程序结束了,很奇怪。

class TestDate
{
     volatile int num = 0;
}

这其实一点都不奇怪,说明num的值被修改了。为什么给属性加了volatile关键字就能成功被修改了呢?其实这要从java的底层java内存模型(JMM)说起,。在JMM模型中,有一个叫做java内存不可见的说法,就是每个线程运行时都有自己的一个线程栈,当线程访问某个对象的变量时,是从主存中(差不多是堆内存)找到该变量的值,然后拷贝一份保存在自己本地内存中,之后该线程就和堆内存就没有任何联系了。
在这里插入图片描述
正是因为这样后面线程每次读取num的值永远是本地线程内存中的值,而并非堆内存中的值,因此第一次是无法跳出循环的。
那为什么加了volatile关键字就能正常结束的原因就很容易想通了。说明加了volatile关键字之后线程每次访问num的值不是从本地内存中读取的,而是从堆内存中读取的。因此volatile可以迫使线程每次去堆内存中读取值。因此后面修改后就能正常结束程序。
在这里插入图片描述

三、继续探究

我们再修改一下代码,我们去掉volatile关键字,然后在循环中打印num的值,再看一下现象。

///上面就不复制啦
},"a").start();
while(testDate.num==0){
            System.out.println(testDate.num);  //打印num
        }

最后可以发现控制台输出了三秒钟的0,居然结束了程序!!!
在这里插入图片描述
很奇怪,很奇怪。。。。为什么去掉了volatile关键字它还是结束了程序,说明他读到的num的值为100。
说明输出num值得这行代码有问题,然后我点进去它的源码一看,好家伙,加了一把synchronized的锁,年轻人不讲武德。这说明volatile关键字和synchronized关键字它们的关系不一般呀,后面的问题就留给小伙伴们自己去发现吧,后面我有时间了解了synchronized关键字也会跟大家分享,希望大家多多支持。

四、总结

其实说白了volatile关键字就是让java内存可见,强迫线程每次取值都是去主存中取值。最后探究java底层原理还是很有意思的,并且面试都喜欢问关于底层实现原理之类的问题。所以我们在学习技术的同时也不要忘了适当探究底层,这对我们理解很多东西都是很有帮助的。最后的最后感谢大家的支持,对于上述有不足和错误的地方,还望大家多多包涵和指正,我一定虚心学习改正,谢谢大家。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值