Happens-Before原则到底规定了什么
Happens-Before 规则
如何理解 Happens-Before 呢?如果望文生义(很多网文也都爱按字面意思翻译成“先行发生”),那就南辕北辙了,Happens-Before 并不是说前面一个操作发生在后续操作的前面,它真正要表达的是:前面一个操作的结果对后续操作是可见的。
就像有心灵感应的两个人,虽然远隔千里,一个人心之所想,另一个人都看得到。Happens-Before 规则就是要保证线程之间的这种“心灵感应”。所以比较正式的说法是:Happens-Before 约束了编译器的优化行为,虽允许编译器优化,但是要求编译器优化后一定遵守 Happens-Before 规则。
在网上的许多资料中对于Happens-Before的7个规则定义如下:
- 程序次序规则:在一个线程内,按照程序代码顺序,书写在前面的操作先行发生于书写在后面的操作。准确地说,应该是控制流顺序而不是程序代码顺序,因为要考虑分支、循环等结构。
- 管程锁定规则:一个unlock操作先行发生于后面对同一个锁的lock操作。这里必须强调的是同一个锁,而"后面"是指时间上的先后顺序。
- volatile变量规则:对一个volatile变量的写操作先行发生于后面对这个变量的读操作,这里的"后面"同样是指时间上的先后顺序。
- 线程启动规则:Thread对象的start()方法先行发生于此线程的每一个动作。
- 线程终止规则:线程中的所有操作都先行发生于对此线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行。
- 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测到是否有中断发生。
- 对象终结规则:一个对象的初始化完成(构造函数执行结束)先行发生于它的finalize()方法的开始。
上述描述的确实有点抽象,不如我们用自己的话来理解一番
1. 程序的顺序性规则
这条规则是指在一个线程中,按照程序顺序,前面的操作 Happens-Before 于后续的任意操作。
2. volatile 变量规则
这条规则是指对一个 volatile 变量的写操作, Happens-Before 于后续对这个 volatile 变量的读操作。
3. 传递性
这条规则是指如果 A Happens-Before B,且 B Happens-Before C,那么 A Happens-Before C。
1.5 版本的并发工具包(java.util.concurrent)就是靠 volatile 语义来搞定可见性的
4. 管程中锁的规则
这条规则是指对一个锁的解锁 Happens-Before 于后续对这个锁的加锁。
要理解这个规则,就首先要了解“管程指的是什么”。管程是一种通用的同步原语,在 Java 中指的就是 synchronized,synchronized 是 Java 里对管程的实现。
管程中的锁在 Java 里是隐式实现的(synchronized)
5. 线程 start() 规则
这条是关于线程启动的。它是指主线程 A 启动子线程 B 后,子线程 B 能够看到主线程在启动子线程 B 前的操作。
6. 线程 join() 规则
这条是关于线程等待的。它是指主线程 A 等待子线程 B 完成(主线程 A 通过调用子线程 B 的 join() 方法实现),当子线程 B 完成后(主线程 A 中 join() 方法返回),主线程能够看到子线程的操作。当然所谓的“看到”,指的是对共享变量的操作。
Reference
Happens-Before原则到底规定了什么的更多相关文章
- 接口Interface解耦的理解
定义一个接口 磁盘 interface Disk(){ void save(File file); } U盘和硬盘都是磁盘,都实现这个接口 class UDisk implement Disk ...
- Java内存模型分析
在学习Java内存模型之前,先了解一下线程通信机制. 1.线程通信机制 在并发编程中,线程之间相互交换信息就是线程通信.目前有两种机制:内存共享与消息传递. 1.1.共享内存 Java采用的就是共享内 ...
- 设计模式之里氏代换原则(LSP)
里氏代换原则(Liskov Substitution Principle, LSP) 1 什么是里氏代换原则 里氏代换原则是由麻省理工学院(MIT)计算机科学实验室的Liskov女士,在1987年的O ...
- (转)CDN——到底用还是不用?
用CDN的七个理由 浏览器从服务器上下载css.js和图片等文件时都要和服务器连接,而大部分浏览器对同一个域名用于下载文件的并发连接数限制在4个,这意味着如果要下载第五个文件就必须等前四个文件中有一个 ...
- 开放封闭原则(Open Closed Principle)
在面向对象的设计中有很多流行的思想,比如说 "所有的成员变量都应该设置为私有(Private)","要避免使用全局变量(Global Variables)",& ...
- Unity3D设计原则
原则1:单一职责 原则2:里氏替换原则(子类扩展但不改变父类功能) 原则3:依赖倒置原则 原则4:接口隔离原则 原则5:迪米特法则(最少知道原则) 原则6:开闭原则 原则1:单一职责原则 说到单一职责 ...
- 当我们说线程安全时,到底在说什么——Java进阶系列(二)
原创文章,同步发自作者个人博客,转载请以超链接形式在文章开头处注明出处http://www.jasongj.com/java/thread_safe/ 多线程编程中的三个核心概念 原子性 这一点,跟数 ...
- 依赖倒置原则(Dependency Inversion Principle)
很多软件工程师都多少在处理 "Bad Design"时有一些痛苦的经历.如果发现这些 "Bad Design" 的始作俑者就是我们自己时,那感觉就更糟糕了.那么 ...
- 里氏替换原则(Liskov Substitution Principle)
开放封闭原则(Open Closed Principle)是构建可维护性和可重用性代码的基础.它强调设计良好的代码可以不通过修改而扩展,新的功能通过添加新的代码来实现,而不需要更改已有的可工作的代码. ...
随机推荐
- javascript——什么是解释型语言?
摘要:<JavaScript基础与案例开发详解>(张孝祥,徐明华)第2章JavaScript环境,本章力求让读者了解JavaScript的开发环境.运行环境,和开发中会遇见的一些问题,做好 ...
- 这些Servlet知识你一定要知道,金九银十大厂面试官都爱问
前言 Servlet是服务器端的Java应用程序,可以生产动态Web页面.透过JSP执行过程可以知道JSP最终被编译成一个.class文件,查看该文件对应的Java类,发现该Java类继承自org.a ...
- 面试官:小伙子,你给我说一下Java Exception 和 Error 的区别吧?
前言 昨天在整理粉丝给我私信的时候,发现了一个挺有意思的事情.是这样的,有一个粉丝朋友私信问我Java 的 Exception 和 Error 有什么区别呢?说他在面试的时候被问到这个问题卡壳了,最后 ...
- 手把手为大家演示fat32转ntfs操作过程,一看就会
fat32和ntfs是两种我们较为常见的u盘或者硬盘格式.它们都有着各自的特点,但是相比之下,使用ntfs文件格式我们可以做出很多fat32不能实现的功能.在日常生活中,我们会面临到需要把fat32转 ...
- iOS 搜索条使用详解
在ios开发中搜索条的使用挺常见的,不过之前一直没用到也没细细研究,最近做外包项目的时候刚好用到,在这里记录一下使用的过程,只要理解了原理,其实还是比较简单的!上传的图片有点大,刚好可以看清楚它的使用 ...
- php8.0正式版新特性和性能优化学习
前言 PHP团队宣布PHP8正式GA(链接).php的发展又开启了新的篇章,PHP8.0.0版本引入了一些重大变更及许多新特性和性能优化机制.火速学习下~ JIT(Just in Time Compi ...
- 【树形dp】【CF161D】distance on a tree + 【P1352】没有上司的舞会
T1题面: 输入点数为N一棵树 求树上长度恰好为K的路径个数 (n < 1e5, k < 500) 这是今天的考试题,也是一道假的紫题,因为我一个根本不会dp的蒟蒻只知道状态就一遍A掉了- ...
- 牛客练习赛67 D牛妹爱数列 题解(dp)
题目链接 题目大意 给你一个长为n的01串,要你进行最少的操作使得这01串变成全为0,求最少操作次数 有两种不同类型的操作 1:翻转一个前缀 2:单调翻转一个元素 题目思路 居然是一个dp,标程讲的很 ...
- C语言讲义——运算符(operator)
运算符(operator) 算数运算符 7种 关系运算符 6种 逻辑运算符 3种 位运算符 6种 赋值运算符 11种 共5类33种 算术运算符 加 + 减 - 乘 * 除 / 取余 % (仅限于整数类 ...
- 获取Win和Linux系统启动时间,类似uptime功能,用于判断是否修改过系统时间
目录 前言 测试代码 Win测试 Linux测试 总结 前言 有时候需要判断系统是否有修改过时间,最简单的方法就是获取当前时间A,然后sleep X秒,然后获取 时间B,如果 时间B - 时间A ≠ ...