voliate关键字的应用误区

voliate关键字的应用误区写下这篇博客也是因为本人之前对voliate关键字理解不透彻,才有了应用误区,希望同样没有理解到位的朋友可以一起踩坑,也欢迎上帝视角明明白白的大佬指出本文的不当之处。先说一下自己之前对voliate的理解,voliate通过内存屏障可以禁止指令重排序和保证可见性,但是不能保证并发安全。禁止指令重排序就不说了,主要说一说如何保证可见性以及为什么不能保证并发安全。首先理解一下一个线程如何去修改…

大家好,又见面了,我是你们的朋友全栈君。

写下这篇博客也是因为本人之前对voliate关键字理解不透彻,才有了应用误区,希望同样没有理解到位的朋友可以一起踩坑,也欢迎上帝视角明明白白的大佬指出本文的不当之处。

先说一下自己之前对voliate的理解,voliate通过内存屏障可以禁止指令重排序和保证可见性,但是不能保证并发安全。禁止指令重排序就不说了,主要说一说如何保证可见性以及为什么不能保证并发安全。

首先理解一下一个线程如何去修改变量a的值,有三步:

第一步从主内存中读取a的值到该线程的工作内存。

第二步在工作内存中修改a。

第三步将a的值刷回主内存。

被voliate修饰的变量在进行写操作时,处理器会多一条Lock指令,Lock指令会将修改后的值直接写进主内存。同时还会让其他线程的工作内存中缓存的a的值失效,这两点就可以保证了可见性,我理解的可见性是指所有线程修改a之前a的值都和主内存中一样,都是一致的。

举个栗子如果有两个thread同时操作voliate修饰变量a,thread1和thread2都将a的值从主内存中读取到工作内存中之后,thread2对a做了修改之后会使thread1工作内存中a的值失效,同时及时地将a的值刷新进主内存,这时候thread1想去修改a发现自己工作内存中的值失效了,就会去主内存中重新读取,这样就避免了典型的并发问题。日常voliate的应用场景中喜欢用来修饰全局变量,曾经以为这样就可以避免该全局变量并发问题,其实不是的。

因为voliate不能将一个非原子性的操作变为原子性。所谓原子性的操作是指该操作在执行期间不受其他操作影响。上面这个对例子中对变量a的值做修改这就不是一个原子性操作,因为这个操作有三步。

还是刚刚那个例子加深一下理解。thread1如果在第一步和第二步中间a的值被thread2修改了,这时候thread1应该在thread2修改之后的a的基础上再做修改,总之thread1的操作结果就要受其他线程影响了。重点来了!voliate可以保证thread1的操作结果正确,但是它不能阻止thread2去影响thread1的操作结果。这就是voliate不能将一个非原子性的操作变为原子性,但是加锁(该变量只能同时被一个线程操作)或者CAS无锁可以,这是题外话。

说了这么多还是没有说为什么voliate不能保证并发安全。先看个情景,还是上面这个例子,刚说thread1在第一步和第二步之间的时候thread2把a修改了,这时候voliate棒棒的一系列骚操作让thread1在执行第二步真正去修改a的时候拿到的还是最新的即thread2修改之后刷新回主内存的值。但是如果thread1在第二步和第三步之间的时候thread2把a修改了呢!这时候thread1已经把a修改完了,已经准备刷回主内存了,这里大家不要和我一样钻牛角尖,之前我也在想,thread2把a修改了刷回主内存那thread1工作内存里a的值不就失效了?thread1已经修改完了就不会再去主内存中读a的值再修改一遍了,它现在要做的是把刚刚修改好a的值也刷回主内存,哦吼,这样一刷就出问题了。这就是voliate不能保证原子性也就是为什么不能保证并发安全的原因。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/143940.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • CCriticalSection类的使用「建议收藏」

    CCriticalSection类的使用「建议收藏」当多个线程访问一个独占性共享资源时,可以使用“临界区”对象。任一时刻只有一个线程可以拥有临界区对象,拥有临界区的线程可以访问被保护起来的资源或代码段,其他希望进入临界区的线程将被挂起等待,直到拥有临界区的线程放弃临界区时为止,这样就保证了不会在同一时刻出现多个线程访问共享资源。      CCriticalSection类的用法非常简单,步骤如下:      定义CCrit

    2022年7月20日
    20
  • oracle数据库的备份与恢复

    oracle数据库的备份与恢复

    2021年8月18日
    54
  • idea mac 快捷键重置(mac重启快捷键是什么)

    智能提示⌘->command⇧->shift⌥->option⬆->上箭头⬇->下箭头⌃->Control编辑快捷键 说明 ⌘+F 在当前窗口查找 ⌘+⇧+F 在全工程查找 ⌘+⇧+⌥+N 查找类中的方法或变量 F3/⇧+F3 移动到搜索结…

    2022年4月12日
    66
  • idea 添加依赖_idea Tomcat

    idea 添加依赖_idea Tomcat使用IDEA编辑器开发项目十分便捷,这里介绍使用IDEA编辑器添加Tomcat1、新建web工程这里有一个已经创建好的web项目2、配置tomcat配置tomcat前,先确保本地已经下载并安装完成了tomcat如果不清楚如何安装tomcat,请参考:安装tomcat点击Run,EditConfigurations……

    2022年10月18日
    3
  • Redis内存碎片率

    Redis内存碎片率

    2021年11月9日
    57
  • sqlserver2012安装教程win10_sql2017安装教程图解

    sqlserver2012安装教程win10_sql2017安装教程图解推荐使用msdn我告诉你网站进行下载,SQLServer2012下载地址先选择服务器如何选择SQLServer2012选择自己要的版本,如果32位机器找x86的版本,如果是64位的请选择x64版本。安装好进入,系统会自动加载ios,找到安装程序,双击打开选择安装然后选择全新的sqlserver独立安装选择安装然后选择全新的sqlserver独立安装…

    2022年8月30日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号