volatile关键字解析

volatile关键字解析

一、内存模型的相关概念

计算机在执行程序时,指令的执行都是在CPU中。在执行指令的过程中,会将临时变量存储在主存(物理内存)中。 CPU执行指令很快,而从内存中读取和写入数据却相对来说很慢,所以就有了高速缓存。 在程序运行时,先将数据从主存复制一份到高速缓存中,然后CPU执行指令时,就可以直接从高速缓存中读取和写入数据,然后刷新到内存中。

这里就产生了一个问题。 比如i是一个共享变量,初始值为0

i = i+1;

在单线程中,CPU执行指令时,先从高速缓存中取出数据,然后进行加1操作,再写入高速缓存中,然后刷新到主存中。 但是多线程中,每一个线程都有自己的工作缓存,线程A,B从高速缓存中读取到数据i的值都为0,在进行加1操作后,写入自己的工作缓存中,再刷新到内存中。 进行两次加法操作,值却为1。

这就是缓存不一致问题。

解决缓存不一致有两个解决方法。

1.在总线加入LOCK#锁

2.使用缓存一致性协议

总线加入锁来阻塞其他线程访问时,会导致线程阻塞,使效率低下。

缓存一致性协议的核心思想是:当线程对一个共享变量进行写操作时,会发出通知,让其他的线程该变量的缓存行置为无效,其他线程操作该变量时,会重新从内存中读取数据。

二、JAVA内存模型

Java内存模型规定所有的变量都存在主存中,每个线程都有自己的工作内存(高速缓存),线程的所有操作都只能操作工作内存,不能操作主存,也不能操作其他线程的工作内存。

三、并发编程中的三个概念

1.原子性

一个操作或多个操作,全部执行不会被其他操作打断。 原子性只针对读取和写入指令。 比如

i = i + 1;

这个代码是没有原子性的,先从高速缓存中取出i的数据,然后进行加1操作,最后写入高速缓存,再刷新到内存中。

如果要保证这个操作的原子性,就可以通过synchronized和lock来实现。

2.可见性

多个线程访问同一个变量时,一个线程修改了变量的值,其他线程能立即看到修改的值。

Java提供了volatile来保证有效性。

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

3.有序性

程序执行顺序按照代码的先后顺序执行。

处理器为了提高程序运行效率,可能会对代码执行顺序进行优化。这里可能会发生指令重排序。

比如两个赋值语句

context = init()
boolean flag = true;

处理器在执行时,可能先执行flag = true,再执行初始化。

多线程执行时,如果后面有根据flag为真,对初始化内容的操作。线程1先执行flag=true,还未初始化内容,线程2根据flag为真执行了对内容的操作,就会导致异常。

while(!flag){
    sleep()
}
dosomething(context);

可以用synchronized和look保证每个时刻只有一个线程访问代码块,相当于顺序执行代码。

四、深入剖析volatile关键字

  1. 保证不同线程对这个变量具有可见性,即一个线程修改了某个变量的值,这个新值对其他线程是立即可见的。
  2. 被volatile修饰的变量禁止指令重排序

多个线程对一个volatile修饰的值进行操作时,可能会导致原子性不一致的问题。 因为volatile只保证了可见性和有序性。

对于自增代码

i++;

由于该操作不是原子性,所以可能存在一个线程从内存中取出值,之后另一个线程对该数据取值操作写入内存。因为可见性是指读操作,之前线程的值已经取出来了,不会变,之后操作得到的值就是1,而不是2。

解决方法是该自增代码加Lock或synchronized

转载于:https://my.oschina.net/u/3371784/blog/2934209

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

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

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


相关推荐

  • COLMO管线机隐藏安装_五金加工厂的设备清单

    COLMO管线机隐藏安装_五金加工厂的设备清单ActiveXControlReport-GeneratedbyActiveXManagerfrom4Developers. ComputerName:YUERGeneratedOn:Tuesday,November21,2006ControlCount:138ControlName:RefEditControlVersion:1.0Status:

    2022年10月15日
    0
  • 通过JS给HTML元素增加、删除和获取属性内容

    通过JS给HTML元素增加、删除和获取属性内容

    2021年11月10日
    43
  • 用iptable防止ddos「建议收藏」

    用iptable防止ddos「建议收藏」DDoSdeflate是一款Linux/centos减轻/防止ddos攻击的一个小程序,相当于软件防火墙。注意,此程序仅仅能抵御较低流量的攻击,大流量攻击连用了上百台高档服务器做了负载均衡的新浪都扛不住,何况一个小小的普通服务器或vps。对此程序不要期望过高。这里仅仅介绍一下,对于一些简单的软件攻击可能还有点作用。CTOHOM制作的DDoSdeflate一键安装脚本:wge…

    2022年5月27日
    43
  • web基础知识总结_Web站点基础阶段包含哪些阶段

    web基础知识总结_Web站点基础阶段包含哪些阶段传统身份验证的方法:HTTP是一种没有状态的协议,也就是它并不知道是谁是访问应用。这里我们把用户看成是客户端,客户端使用用户名还有密码通过了身份验证,不过下回这个客户端再发送请求时候,还得再验证一下。解决的方法就是,当用户请求登录的时候,如果没有问题,我们在服务端生成一条记录,这个记录里可以说明一下登录的用户是谁,然后把这条记录的ID号发送给客户端,客户端收到以后把这个ID号存储在C…

    2025年7月11日
    1
  • managementobjectsearch_beanpropertyrowmapper

    managementobjectsearch_beanpropertyrowmapperclassWin32_Service:Win32_BaseService{ booleanAcceptPause; booleanAcceptStop; stringCaption; uint32CheckPoint; stringCreationClassName; stringDescription; booleanDesktopInteract; st

    2022年10月2日
    1
  • DeepLab v3_deeplab模型导出

    DeepLab v3_deeplab模型导出大年初一我居然在更博客。今年过年由于病毒横行,没有串门没有聚餐,整个人闲的没事干。。。医生真是不容易,忙得团团转还有生命危险,新希望他们平安。本篇不属于初级教程。如果完全看不懂请自行谷歌或搜索作者博客。deeplab官方提供了多种backbone,通过train.py中传递参数,–model_variant=”resnet_v1_101_beta”\可以更改backbone。…

    2022年9月25日
    0

发表回复

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

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