服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|JavaScript|易语言|

服务器之家 - 编程语言 - Java教程 - Java并发编程-volatile可见性详解

Java并发编程-volatile可见性详解

2021-07-25 15:38寻筝 Java教程

这篇文章主要介绍了Java并发编程-volatile可见性详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

要学习好java的多线程,就一定得对volatile关键字的作用机制了熟于胸。最近博主看了大量关于volatile的相关博客,对其有了一点初步的理解和认识,下面通过自己的话叙述整理一遍。

有什么用?

volatile主要对所修饰的变量提供两个功能

可见性
防止指令重排序
<br>本篇博客主要对volatile可见性进行探讨,以后发表关于指令重排序的博文。

什么是可见性?

Java并发编程-volatile可见性详解

把java内存模型(jmm)展示得很详细了,简单概括一下

1.每个thread有一个属于自己的工作内存(可以理解为每个厨师有一个属于自己的铁锅)
2.所有thread共用一个主内存(餐厅所有的厨师共用同一个冰箱)
3.每个thread操作数据之前都会去主内存中获取数据(厨师炒菜之前都要去冰箱里拿食材)

  1. thread:厨师
  2. 工作内存:铁锅
  3. store&load:放熟食,取食材
  4. 主内存:冰箱

读者可思考以下情景:<br> 餐厅来了一位顾客点了一份红烧肉,此时有两位大厨(假设大厨之间互不通信),由于互不通信,所以两位大厨都打开冰箱取出食材开始炒菜。 最后炒出了两份红烧肉,顾客只要一份。为什么会造成这种结果?

由于大厨之间没有可见性。

将此情景放在java中即是:<br> 线程a从主内存中取了一个变量到工作内存中,操作完毕后没有及时放回主内存中,于是线程b去取这个变量已经过期了,取的是线程a操作之前的变量。

如何拥有可见性?

先介绍一下java内存模型中定义的8种工作内存与主内存之间的原子操作

  1. lock( 锁定 ):作用于主内存的变量,把一个变量标识为一条线程独占的状态。
  2. unlock(解锁):作用于主内存的变量,把一个处于锁定的变量释放出来,释放变量才可以被其他线程锁定。
  3. read(读取):作用于主内存的变量,把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用。
  4. load(载入):作用于***工作内存***的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中。
  5. use(使用):作用于***工作内***存种的变量,它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作。
  6. assign(赋值):作用于***工作内存***中的变量,它把一个从执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
  7. store(存储):作用于***工作内存***的变量,它把工作内存中一个变量的值传送到主内存中,以便随后的write操作使用
  8. write(写入):作用于主内存的变量,它把store操作从工作内存中得到的值放入主内存的变量中。

读取赋值一个普通变量的情况

Java并发编程-volatile可见性详解

发起read操作到write操作套流程的时间里,线程2随时都有可能对这个主内存对象发起第二套操作

有什么危害呢?
假设主内存中有一个

?
1
int a=0;

线程1和线程2分别执行一次,理想状态下最终a的值为2.

?
1
a++;

线程1在执行了assign操作之后变量a的真实值已经从0变成了1,但是这个过程发生在工作内存中对其他线程不可见,若线程2此时对变量a的操作,读取到的值仍然为0,因为没有可见性,线程2的操作也仅仅是重复了线程1的操作,再次让a从0变成了1。并没有达到期望的a=2。

读取赋值一个volatile变量的情况

Java并发编程-volatile可见性详解

操作更严格:

use之前不能被read&load
assign之后必须紧跟store&write
也就是说 read-load-use 和 assign-store-write成为了两个不可分割的原子操作

尽管这时候在use和assign之间依然有一段真空期,有可能变量会被其他线程读取,但是无论在哪一个时间点主内存的变量和任一工作内存的变量的值都是相等的。这个特性就导致了volatile变量不适合参与到依赖当前值的运算,如自增。 那么依靠可见性的特点volatile可以用在哪些地方呢? 《java虚拟机》提到:

运算结果并不依赖变量的当前值(即结果对产生中间结果不依赖),或者能够确保只有单一的线程修改变量的值
通常volatile用做保存某个状态的boolean值。

以上所述是小编给大家介绍的java并发编程-volatile可见性详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!

原文链接:https://my.oschina.net/keepwent/blog/1814387

延伸 · 阅读

精彩推荐
  • Java教程java公众平台通用接口工具类HttpConnectUtil实例代码

    java公众平台通用接口工具类HttpConnectUtil实例代码

    下面小编就为大家分享一篇java公众平台通用接口工具类HttpConnectUtil实例代码,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    guishengbin9012021-03-15
  • Java教程学习spring事务与消息队列

    学习spring事务与消息队列

    这篇文章主要为大家详细介绍了spring事务与消息队列,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    登顶3662020-06-22
  • Java教程详解springBoot启动时找不到或无法加载主类解决办法

    详解springBoot启动时找不到或无法加载主类解决办法

    这篇文章主要介绍了详解springBoot启动时找不到或无法加载主类解决办法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价...

    DE.Marcia12112020-09-16
  • Java教程java微信公众号企业付款开发

    java微信公众号企业付款开发

    这篇文章主要为大家详细介绍了java微信公众号企业付款开发,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    shaomiaojava7132021-06-02
  • Java教程Java抽奖算法第二例

    Java抽奖算法第二例

    这篇文章主要为大家详细介绍了Java抽奖算法,根据概率将奖品划分区间,每个区间代表一个奖品,然后抽取随机数,具有一定的参考价值,感兴趣的小伙伴...

    go2shell7652020-06-02
  • Java教程解析本地方法映射Java层的数据类型

    解析本地方法映射Java层的数据类型

    这篇文章给大家介绍了本地方法映射Java层的数据类型,包括基础类型映射,引用类型映射等等,对java层数据类型映射相关知识,感兴趣的朋友跟随脚本之...

    github6482021-04-13
  • Java教程Java中的字符编码问题处理心得总结

    Java中的字符编码问题处理心得总结

    Java中的String类默认是Unicode编码,大家平常所说的UTF-8就是使用最广的一种unicode的实现方式,以下我们还是来看一下Java中的字符编码问题处理心得总结: ...

    阿诺1992020-05-21
  • Java教程JAVA时间日期处理类实例

    JAVA时间日期处理类实例

    这篇文章主要介绍了JAVA时间日期处理类,可实现遍历两个日期之间的每一天的功能,涉及针对日期的常见操作技巧,需要的朋友可以参考下 ...

    MagicYK3272019-12-16