热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java精通并发volatile与内存屏障的重要语义详细分析

在上一次https:www.cnblogs.comwebor2006protectedp12595201.html咱们已经对于volatile关键字的作用进行了一定的了解,这里回顾

在上一次https://www.cnblogs.com/webor2006/protected/p/12595201.html咱们已经对于volatile关键字的作用进行了一定的了解,这里回顾一下:

Java精通并发-volatile与内存屏障的重要语义详细分析 

上一次对于第一条作用进行了详细的解读了,接下来则来解读一下剩下的两条:防止指令重排序、实现变量的可见性。而这俩其实都是通过一种手段来实现的:内存屏障(memory barrier),所以要想搞清楚这这两条,必须得先来理解内存屏障这个概念,所以接下来重点来搞清楚内存屏障这个平常听得比较少的这个概念。

这其实涉及到JIT(Just In Time)的一些功能,在现代化的JVM编译器当中,它会根据我们所写的代码的情况自动的一定程序的优化,其中优化当中就有一个可能就是会对咱们的指令进行一定的修改,比如按照顺序执行了三条指令:1、2、3【对应我们的代码顺序】,但是在编译完之后可能生成的字节码会变成3、2、1,或1、3、2等,也就是对指令进行重排序了,这里用一个简单的例子来直观的看一下指令重排序的大概思想:

int a = 0;
int b = 1;

a++;

重排后可能为:

int a = 0;
a++;
int b = 0;

对于这个重排序其实是编译器为了让我们的程序执行的性能更高而采取的一种优化手段,但是!!!在极端情况下这种指令重排序的优化手段并不是我们需要的,所以此时就需要防止某些指令重排序,而是按我们所编写的代码的顺序来执行。对于指令重排序而言,在单线程环境下肯定是没任何问题的,如果有问题也不可能出现这种优化策略了,重点是在多线程的环境下这种所谓优化的指令重排序策略可能就会产生问题,而这个volatile关键字就具备这种防止指令重排序的功能。

阐述内存屏障(memeory barrier):

volatile写入操作:

这里先来看一个简单代码:

int a = 1;
String s = "Hello";

volatile boolean v = false; //写入操作

此时则会在volatile这句代码之前和之后插入相应的内存屏障:

int a = 1;
String s = "Hello";
内存屏障
volatile boolean v = false; //写入操作
内存屏障

而内存屏障是存在有分类的,这里给内存屏障再细化一下则为:

int a = 1;
String s = "Hello";
内存屏障 (Release Barrier,释放屏障volatile boolean v = false; //写入操作
内存屏障(Store Barrier,存储屏障

很显然这个屏障我们肉眼是看不到的,是借助于volatile来实现的,那对于这俩个屏障对于程序有啥作用呢?下面来解释一下:

  • Release Barrier:防止下面的volatile与上面的所有操作的指令重排序,并可以让在内存屏障之前所发生的读写操作都能立刻的发布到所有的程序当中,其它线程就能立刻看到其修改的结果。啥意思?
    Java精通并发-volatile与内存屏障的重要语义详细分析
  • Store Barrier:它的重要作用是刷新处理器的缓存,结果是可以确保该存储屏障之前一切的操作所生成的结果对于其他处理器来说都可见,也就是:
    Java精通并发-volatile与内存屏障的重要语义详细分析

volatile读取操作:

对于volatile的读操作其内存屏障又是不一样的,下面来看一下:

int a = 1;
String s = "Hello";
内存屏障 (Release Barrier,释放屏障)
volatile boolean v = false; //写入操作
内存屏障(Store Barrier,存储屏障)

boolean v1 = v; //读取操作

int a = 1;
String s = "Hello";

此时由于遇到了volatile的读取操作,则又会产生内存屏障了,它有别于之前看到的写入的屏障,如下:

int a = 1;
String s = "Hello";
内存屏障 (Release Barrier,释放屏障)
volatile boolean v = false; //写入操作
内存屏障(Store Barrier,存储屏障)

内存屏障 (Load Barrier,加载屏障)
boolean v1 = v; //读取操作
内存屏障 (Acquire Barrier,获取屏障)

int a = 1;
String s = "Hello";

那这两种屏障又有何义呢?

  • Load Barrier:可以刷新处理器缓存,同步其他处理器对该volatile变量的修改结果。也就是:
    Java精通并发-volatile与内存屏障的重要语义详细分析
  • Acquire Barrier:可以防止上面的volatile读取操作与下面的所有操作语句的指令重排序。
    Java精通并发-volatile与内存屏障的重要语义详细分析

可以发现:

Java精通并发-volatile与内存屏障的重要语义详细分析

Java精通并发-volatile与内存屏障的重要语义详细分析

对于volatile关键字变量的读写操作,本质上都是通过内存屏障来执行的,而内存屏障兼具了如下两方面的能力:

1、防止指令重排序。

2、实现变量内存的可见性。

所以:

Java精通并发-volatile与内存屏障的重要语义详细分析

最后总结一下:

1、对于读取操作来说,volatile可以确保该操作与其后续的所有读写操作都不会进行指令重排序。

2、对于修改操作来说,valatile可以确保该操作与其上面的所有读写操作都不会进行指令重排序。

注意:

在上面的举例中都是Java的原生数据类型:

Java精通并发-volatile与内存屏障的重要语义详细分析

如果是一个引用类型呢?比如说ArrayList,那对于volatile的内存屏障功效是不起作用的,为啥?因为ArrayList中的读写操作都不是原子的,比如读操作,得先找到元素的地址,然后再进行读取,但是!!如果将ArrayList的引用赋值给另一个volatile的ArrayList,这就可以确保原子操作,也就有了volatile相关的功效了。

再论volatile和锁【面试题】:

在上一次volatile的学习中已经针对它们俩的相同与不同点做了一个阐述,回忆一下:

Java精通并发-volatile与内存屏障的重要语义详细分析

这里由于学到了内存屏障的知识点,所以需要再拉出来进一步阐述一下,对于synchronized代码块而言,对应的字节码指令我们都知道会是如下:

monitorenter
.....
monitorexit

我们知道锁的功能比volatile功能更强大,因为它有排他性,对于volatile它不是有指令重排序和内存可见性的功效,那锁有木有呢?当然有,所以加上这个功效之后的锁背后的形态就会变为:

monitorenter
内存屏障 (Acquire Barrier,获取屏障)//刷新处理器缓存,同步其他处理器对该volatile变量的修改结果,也就是获取最新的值
.....
内存屏障 (Release Barrier,释放屏障)//也就是将处理结果发布出去,刷新处理器缓存
monitorexit

以上就是对于同步锁的一个完整的形态。

总结:

1、volatile关键字自身的劣势:它相比不使用volatile的变量而言,性能有损失,因为对于有volatile的变量,则每次都是会从主内存(高速缓存)中来获取了,而如果不使用volatile的变量,则会直接从寄存器上获取,要明白,寄存器要比内存获取快多的,所以这个关键字不要烂用。

2、volatile相比锁,优点是volatile不存在阻塞,也不会进行用户态到内核态的切换,而锁肯定是要阻塞且会进行用户和内核态的切换;缺点是它不具备锁的排它性。

通过这两篇的总结,我觉得就已经能彻底来理清这个关键字的含义了,真的涉及到的概念还是很难理解的。


推荐阅读
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • PHP 5.5.0rc1 发布:深入解析 Zend OPcache
    2013年5月9日,PHP官方发布了PHP 5.5.0rc1和PHP 5.4.15正式版,这两个版本均支持64位环境。本文将详细介绍Zend OPcache的功能及其在Windows环境下的配置与测试。 ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • Explore how Matterverse is redefining the metaverse experience, creating immersive and meaningful virtual environments that foster genuine connections and economic opportunities. ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 深入理解Java中的volatile、内存屏障与CPU指令
    本文详细探讨了Java中volatile关键字的作用机制,以及其与内存屏障和CPU指令之间的关系。通过具体示例和专业解析,帮助读者更好地理解多线程编程中的同步问题。 ... [详细]
  • DNN Community 和 Professional 版本的主要差异
    本文详细解析了 DotNetNuke (DNN) 的两种主要版本:Community 和 Professional。通过对比两者的功能和附加组件,帮助用户选择最适合其需求的版本。 ... [详细]
  • 尽管某些细分市场如WAN优化表现不佳,但全球运营商路由器和交换机市场持续增长。根据最新研究,该市场预计在2023年达到202亿美元的规模。 ... [详细]
  • 并发编程:深入理解设计原理与优化
    本文探讨了并发编程中的关键设计原则,特别是Java内存模型(JMM)的happens-before规则及其对多线程编程的影响。文章详细介绍了DCL双重检查锁定模式的问题及解决方案,并总结了不同处理器和内存模型之间的关系,旨在为程序员提供更深入的理解和最佳实践。 ... [详细]
  • 本文详细介绍了如何准备和安装 Eclipse 开发环境及其相关插件,包括 JDK、Tomcat、Struts 等组件的安装步骤及配置方法。 ... [详细]
  • 本文作者分享了在阿里巴巴获得实习offer的经历,包括五轮面试的详细内容和经验总结。其中四轮为技术面试,一轮为HR面试,涵盖了大量的Java技术和项目实践经验。 ... [详细]
  • 将Web服务部署到Tomcat
    本文介绍了如何在JDeveloper 12c中创建一个Java项目,并将其打包为Web服务,然后部署到Tomcat服务器。内容涵盖从项目创建、编写Web服务代码、配置相关XML文件到最终的本地部署和验证。 ... [详细]
  • 本文介绍如何在QT框架中使用QWebSocket和QTcpSocket实现SSL加密通信,涵盖单向认证设置。单向认证常见于Web通信场景,其中客户端验证服务端证书,而服务端不验证客户端证书。 ... [详细]
  • ElasticSearch 集群监控与优化
    本文详细介绍了如何有效地监控 ElasticSearch 集群,涵盖了关键性能指标、集群健康状况、统计信息以及内存和垃圾回收的监控方法。 ... [详细]
author-avatar
卡瑙娇管
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有