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)
上一篇 2021年6月17日 上午9:00
下一篇 2021年6月17日 上午10:00


相关推荐

  • 黄页网址大全推荐_常用的网站

    黄页网址大全推荐_常用的网站可以试试这个,https://tongcheng360.com页面干净整洁,页面使用缓存技术,打开速度非常快,包括公司简介,发布公司产品,发布公司新闻,公司如有特殊需求,可进行定制化开发,大大节省了公司的运维和开发成本并且具有同城分类信息的功能b站操作视频https://www.bilibili.com/video/BV1jy4y1L7Z1…

    2022年5月3日
    262
  • 三星galaxy S4快捷功能

    三星galaxy S4快捷功能

    2021年12月15日
    46
  • Redis 主从复制

    Redis 主从复制大家好,我是小林哥。又来图解Redis啦。我在前两篇已经给大家图解了AOF和RDB,这两个持久化技术保证了即使在服务器重启的情况下也不会丢失数据(或少量损失)。不过,由于数据都是存储在一台服务器上,如果出事就完犊子了,比如:如果服务器发生了宕机,由于数据恢复是需要点时间,那么这个期间是无法服务新的请求的;如果这台服务器的硬盘出现了故障,可能数据就都丢失了。要避免这种单点故障,最好的办法是将数据备份到其他服务器上,让这些服务器也可以对外提供服务,这样即使有一台服务器出现了故障,其他服

    2022年8月13日
    6
  • RSA算法详解及C语言实现

    RSA算法详解及C语言实现1 什么是 RSARSA 公钥加密算法是 1977 年由罗纳德 李维斯特 RonRivest 阿迪 萨莫尔 AdiShamir 和伦纳德 阿德曼 LeonardAdlem 一起提出的 1987 年首次公布 当时他们三人都在麻省理工学院工作 RSA 就是他们三人姓氏开头字母拼在一起组成的 RSA 是目前最有影响力的公钥加密算法 它能够抵抗到目前为止已知的绝大多数密码攻击 已被 ISO 推荐为公钥数

    2026年3月18日
    2
  • 最新指南 | Midjourney合租教程,这个拼车平台比较靠谱

    最新指南 | Midjourney合租教程,这个拼车平台比较靠谱

    2026年3月15日
    1
  • 一比一还原axios源码(二)—— 请求响应处理

    上一章,我们开发了一些简单的代码,这部分代码最最核心的一个方法就是buildURL,应对了把对象处理成query参数的方方面面。虽然我们现在可以发起简单的请求了,但是第一,我们无法接收到服务器的响应,

    2022年3月25日
    45

发表回复

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

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