0

0

【死磕Java并发】-----Java内存模型之重排序

黄舟

黄舟

发布时间:2017-02-24 10:05:26

|

1561人浏览过

|

来源于php中文网

原创

在执行程序时,为了提供性能,处理器和编译器常常会对指令进行重排序,但是不能随意重排序,不是你想怎么排序就怎么排序,它需要满足以下两个条件: 

1. 在单线程环境下不能改变程序运行的结果;
2. 存在数据依赖关系的不允许重排序

如果看过LZ上篇博客的就会知道,其实这两点可以归结于一点:无法通过happens-before原则推导出来的,JMM允许任意的排序。

as-if-serial语义

as-if-serial语义的意思是,所有的操作均可以为了优化而被重排序,但是你必须要保证重排序后执行的结果不能被改变,编译器、runtime、处理器都必须遵守as-if-serial语义。注意as-if-serial只保证单线程环境,多线程环境下无效。

下面我们用一个简单的示例来说明:

int a = 1 ;      //A
int b = 2 ;      //B
int c = a + b;   //C

A、B、C三个操作存在如下关系:A、B不存在数据依赖关系,A和C、B和C存在数据依赖关系,因此在进行重排序的时候,A、B可以随意排序,但是必须位于C的前面,执行顺序可以是A –> B –> C或者B –> A –> C。但是无论是何种执行顺序最终的结果C总是等于3。

立即学习Java免费学习笔记(深入)”;

as-if-serail语义把单线程程序保护起来了,它可以保证在重排序的前提下程序的最终结果始终都是一致的。

其实对于上段代码,他们存在这样的happen-before关系:

  1. A happens-before B

  2. B happens-before C

  3. A happens-before C

1、2是程序顺序次序规则,3是传递性。但是,不是说通过重排序,B可能会排在A之前执行么,为何还会存在存在A happens-beforeB呢?这里再次申明A happens-before B不是A一定会在B之前执行,而是A的对B可见,但是相对于这个程序A的执行结果不需要对B可见,且他们重排序后不会影响结果,所以JMM不会认为这种重排序非法。

我们需要明白这点:在不改变程序执行结果的前提下,尽可能提高程序的运行效率。

剪映专业版
剪映专业版

一款全能易用的桌面端剪辑软件

下载

下面我们在看一段有意思的代码:

public class RecordExample1 {
    public static void main(String[] args){        
    int a = 1;        
    int b = 2;        
    try {
            a = 3;           //A
            b = 1 / 0;       //B
        } catch (Exception e) {

        } finally {
            System.out.println("a = " + a);
        }
    }
}

按照重排序的规则,操作A与操作B有可能会进行重排序,如果重排序了,B会抛出异常( / by zero),此时A语句一定会执行不到,那么a还会等于3么?如果按照as-if-serial原则它就改变了程序的结果。其实JVM对异常做了一种特殊的处理,为了保证as-if-serial语义,Java异常处理机制对重排序做了一种特殊的处理:JIT在重排序时会在catch语句中插入错误代偿代码(a = 3),这样做虽然会导致cathc里面的逻辑变得复杂,但是JIT优化原则是:尽可能地优化程序正常运行下的逻辑,哪怕以catch块逻辑变得复杂为代价。

重排序对多线程的影响

在单线程环境下由于as-if-serial语义,重排序无法影响最终的结果,但是对于多线程环境呢?

如下代码(volatile的经典用法):

public class RecordExample2 {
    int a = 0;    boolean flag = false;    
    /**
     * A线程执行
     */
    public void writer(){
        a = 1;                  
        // 1
        flag = true;            
        // 2
    }    /**
     * B线程执行
     */
    public void read(){        
    if(flag){                  
    // 3
           int i = a + a;          
           // 4
        }
    }

}

A线程执行writer(),线程B执行read(),线程B在执行时能否读到 a = 1 呢?答案是不一定(注:X86CPU不支持写写重排序,如果是在x86上面操作,这个一定会是a=1,LZ搞了好久都没有测试出来,最后查资料才发现)。

由于操作1 和操作2 之间没有数据依赖性,所以可以进行重排序处理,操作3 和操作4 之间也没有数据依赖性,他们亦可以进行重排序,但是操作3 和操作4 之间存在控制依赖性。假如操作1 和操作2 之间重排序:

这里写图片描述

按照这种执行顺序线程B肯定读不到线程A设置的a值,在这里多线程的语义就已经被重排序破坏了。

操作3 和操作4 之间也可以重排序,这里就不阐述了。但是他们之间存在一个控制依赖的关系,因为只有操作3 成立操作4 才会执行。当代码中存在控制依赖性时,会影响指令序列的执行的并行度,所以编译器和处理器会采用猜测执行来克服控制依赖对并行度的影响。假如操作3 和操作4重排序了,操作4 先执行,则先会把计算结果临时保存到重排序缓冲中,当操作3 为真时才会将计算结果写入变量i中

通过上面的分析,重排序不会影响单线程环境的执行结果,但是会破坏多线程的执行语义

 以上就是【死磕Java并发】-----Java内存模型之重排序的内容,更多相关内容请关注PHP中文网(www.php.cn)!

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
全国统一发票查询平台入口合集
全国统一发票查询平台入口合集

本专题整合了全国统一发票查询入口地址合集,阅读专题下面的文章了解更多详细入口。

19

2026.02.03

短剧入口地址汇总
短剧入口地址汇总

本专题整合了短剧app推荐平台,阅读专题下面的文章了解更多详细入口。

27

2026.02.03

植物大战僵尸版本入口地址汇总
植物大战僵尸版本入口地址汇总

本专题整合了植物大战僵尸版本入口地址汇总,前往文章中寻找想要的答案。

15

2026.02.03

c语言中/相关合集
c语言中/相关合集

本专题整合了c语言中/的用法、含义解释。阅读专题下面的文章了解更多详细内容。

3

2026.02.03

漫蛙漫画网页版入口与正版在线阅读 漫蛙MANWA官网访问专题
漫蛙漫画网页版入口与正版在线阅读 漫蛙MANWA官网访问专题

本专题围绕漫蛙漫画(Manwa / Manwa2)官网网页版入口进行整理,涵盖漫蛙漫画官方主页访问方式、网页版在线阅读入口、台版正版漫画浏览说明及基础使用指引,帮助用户快速进入漫蛙漫画官网,稳定在线阅读正版漫画内容,避免误入非官方页面。

13

2026.02.03

Yandex官网入口与俄罗斯搜索引擎访问指南 Yandex中文登录与网页版入口
Yandex官网入口与俄罗斯搜索引擎访问指南 Yandex中文登录与网页版入口

本专题汇总了俄罗斯知名搜索引擎 Yandex 的官网入口、免登录访问地址、中文登录方法与网页版使用指南,帮助用户稳定访问 Yandex 官网,并提供一站式入口汇总。无论是登录入口还是在线搜索,用户都能快速获取最新稳定的访问链接与使用指南。

114

2026.02.03

Java 设计模式与重构实践
Java 设计模式与重构实践

本专题专注讲解 Java 中常用的设计模式,包括单例模式、工厂模式、观察者模式、策略模式等,并结合代码重构实践,帮助学习者掌握 如何运用设计模式优化代码结构,提高代码的可读性、可维护性和扩展性。通过具体示例,展示设计模式如何解决实际开发中的复杂问题。

3

2026.02.03

C# 并发与异步编程
C# 并发与异步编程

本专题系统讲解 C# 异步编程与并发控制,重点介绍 async 和 await 关键字、Task 类、线程池管理、并发数据结构、死锁与线程安全问题。通过多个实战项目,帮助学习者掌握 如何在 C# 中编写高效的异步代码,提升应用的并发性能与响应速度。

2

2026.02.03

Python 强化学习与深度Q网络(DQN)
Python 强化学习与深度Q网络(DQN)

本专题深入讲解 Python 在强化学习(Reinforcement Learning)中的应用,重点介绍 深度Q网络(DQN) 及其实现方法,涵盖 Q-learning 算法、深度学习与神经网络的结合、环境模拟与奖励机制设计、探索与利用的平衡等。通过构建一个简单的游戏AI,帮助学习者掌握 如何使用 Python 训练智能体在动态环境中作出决策。

3

2026.02.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3.1万人学习

C# 教程
C# 教程

共94课时 | 8.3万人学习

Java 教程
Java 教程

共578课时 | 56万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号