【JUC】十八、happens-before先行发生原则

文章目录

  • 1、先行发生原则happens-before
  • 2、happens-before总原则
  • 3、8条happens-before规则
  • 4、案例

1、先行发生原则happens-before

在Java中,Happends-Before本质上是规定了一种可见性, A Happends-Before B,则A发生过的事情对B来说是可见的,不论A事件和B事件是否发生在同一个线程里。

  • happens-before体现的是对可见性和有序性的约束。
  • happens-before是并发环境下,两个操作是否可能存在冲突的判断依据

在这里插入图片描述

y一定等于5

如果线程A的操作(x=5)先行发生于线程B的操作(y=x),或者说这两个事件存在先行发生原则,那y=5一定成立,反之则不一定,因为x=5的改变可能还没从A线程的工作内存刷回主内存,线程就暂时挂起了。

但如果Java内存模型中的有序性都得靠volatile和synchronized来实现,就非常繁琐,而且日常开发也没见处处加这些关键字,这是因为谁先谁后在先行发生原则里已经立好了规矩。

2、happens-before总原则

1)如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前。

2) 两个操作之间存在happens-before关系,并不意味着一定要按照happens-before原则制定的顺序来执行,如果重排序之后的执行结果与按照happens-before关系来执行的结果一致,那么这种重排序并不非法

举例:

值日表里写了周一张三,周二李四,但现在张三周一临时有事,和李四换班后,教室还是能打扫干净

3、8条happens-before规则

1> 次序规则一个线程内,按照代码顺序,写在前面的操作先于写在后面的操作

直白讲就是:同一个线程,前面一个操作把变量x赋值为1,那后面一个操作肯定知道x已经变成1了

2> 锁定规则:一个unLock操作先行发生于后面(这里的"后面"是指时间上的先后)对同一个锁的lock操作

直白说就是:一定是:A线程unlock后,B线程才能对同一个锁lock

Lock lock = new ReentrantLock();lock.lock();
try{}finally{//先lock.unlock();
}
//后
lock.lock();
try{}finally{lock.unlock();
}

3> volatile变量规则 :对一个volatile变量的写操作先行发生于后面对这个变量的读操作,前面的写对后面的读是可见的,这里的”后面“同样是指时间上的先后

4> 传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C

5> 线程启动规则:Thread对象的start()方法先行发生于此线程的每一个动作

执行顺序一定是第4行先,第2行后:

Thread t1 = new Thread(() -> {System.out.println("QWE");   //后},"t1");
t1.start();  //先

6> 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()检测到是否发生中断。

直白说:检测到中断事件发生(检测到中断标志位变了),是先发生了interrupt方法的调用。一定是先发烧了,温度计才能检测到体温变了。

7> 线程终止规则:线程中的所有操作都先行发生于对此线程的终止检测,我们可以通过isAlive()等手段检测线程是否已经终止执行

直白说:线程中的操作(比如run方法体)先全部执行完,线程才终止

8> 对象终结规则:一个对象的初始化完成(构造函数执行结束) 先行发生于它的finalize()方法的开始

翻译:肯定是先new了一个对象,才能垃圾回收这个对象

4、案例

private int value = 0;private int getValue(){return value;
}private int setValue(){return ++value;
}

现在有线程A和线程B,线程A(在时间上先)调用了setValue方法,然后线程B调用同一对象的getValue方法,那线程B的返回值是?

对照上面的8条规则:
  • 两个方法在不同线程,第一条规则用不上
  • 两个方法都未加锁,规则2也pass
  • 共享变量value没有加volatile,规则3pass
  • 先行发生规则不等价于时间上的先,这里目前直接没有已知的先行发生规则,无从传递,pass

⇒ 无法通过happens-before原则推导出线程A happens-before线程B,虽然可以确认在时间上线程A优先于线程B,无法确认线程B获得的结果是什么,所以这段代码不是线程安全的。

怎么修复?

方式一:加synchronized,如下,这样性能损失太大

private int value = 0;private synchronized int getValue(){return value;
}private synchronized int setValue(){return ++value;
}

方式二:把value定义为volatile变量,由于setter方法对value的修改不依赖value的原值,满足volatile关键字使用场景

private volatile int value = 0;private int getValue(){return value;  //利用volatile保证读取操作的可见性
}private synchronized int setValue(){  //利用synchronized保证复合操作的原子性return ++value; 
}

利用volatile保证读取操作的可见性,利用synchronized保证复合操作的原子性,结合使用锁和volatile 变量来减少同步的开销

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/234227.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

项目设计---网页五子棋

文章目录 一. 项目描述二. 核心技术三. 需求分析概要设计四. 详细设计4.1 实现用户模块4.1.1 约定前后端交互接口4.1.2 实现数据库设计4.1.3 客户端页面展示4.1.4 服务器功能实现 4.2 实现匹配模块4.2.1 约定前后端交互接口4.2.2 客户端页面展示4.2.3 服务器功能实现 4.3 实现对…

内网渗透隧道技术一netsh

隧道技术 百度百科: 网络隧道技术指的是利用一种网络协议来传输另一种网络协议,它主要利用网络隧道协议来实现这种功能。网络隧道技术涉及了三种网络协议,即网络隧道协议、隧道协议下面的承载协议和隧道协议所承载的被承载协议 在网络安全中…

【bug篇】Tomcat一直报错,但是代码没问题

代码都没有问题&#xff0c;就是报404错误&#xff0c;原因竟然是版本不兼容&#xff0c;搞了我好长时间&#xff0c;简直麻了&#xff01;&#xff01;&#xff01; 因为我的Tomcat是11版本的&#xff0c;所以导入的servlet和jsp依赖应该是下面这些&#xff1a; <!-- Serv…

【C语言期末不挂科——指针进阶篇】【上】

C语言进阶篇【上】 文章目录 C语言进阶篇【上】字符指针数组指针数组传参和指针传参  数组传参  一级指针传参  二级指针传参 前言&#xff1a; 我们在指针初阶篇学习了&#xff1a; 1、指针就是个变量&#xff0c;用来存放地址&#xff0c;地址唯一标识一块空间。 2、指…

37.从0到上线三天搭建个人网站(第一天)

点赞收藏加关注&#xff0c;你也能住大别墅&#xff01; 挑战三天搭建个人网站 从0到上线 一、项目的主要功能 1.作为自己在网上的一个工作室。 2.发帖 3.展示个人项目连接 4.介绍自己&#xff08;没准儿还能接点活儿&#xff09; 二、UI风格参考 三、技术选型 1.前端&a…

Flask 实现Token认证机制

在Flask框架中&#xff0c;实现Token认证机制并不是一件复杂的事情。除了使用官方提供的flask_httpauth模块或者第三方模块flask-jwt&#xff0c;我们还可以考虑自己实现一个简易版的Token认证工具。自定义Token认证机制的本质是生成一个令牌&#xff08;Token&#xff09;&…

4.5-容器之间的link

我们在实际项目中可能会有种需求&#xff0c;假如我们有个后台项目&#xff0c;它要访问数据库&#xff0c;比如MySQL&#xff0c;它想要访问数据库&#xff0c;就需要数据库的ip和端口。如果有两个容器&#xff0c;一个容器启动的是数据库的MySQL服务&#xff0c;另一个容器启…

二叉树题目:祖父结点值为偶数的结点和

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;祖父结点值为偶数的结点和 出处&#xff1a;1315. 祖父结点值为偶数的结点和 难度 5 级 题目描述 要求 给定二…

13:kotlin类和对象 -- 属性(Properties)

定义属性 类属性可使用var和val定义 class Address {var name: String "Holmes, Sherlock"var street: String "Baker"var city: String "London"var state: String? nullvar zip: String "123456" }属性使用 fun copyAddres…

【MySQL:从零开始练级】环境安装与基础认识

hello大家好&#xff0c;失踪人口回归&#xff0c;今天开始新专栏MySQL&#xff1a;从零开始练级,今天给大家分享MySQL的环境安装与基础认识&#xff0c;希望大家能有所学习收获。 目录 1️⃣ Centos 7环境下安装 2️⃣什么是数据库 3️⃣服务器、数据库、表关系 4️⃣MySQ…

轻盈未来:气膜建筑的绿色时尚

随着可持续发展理念的日益深入人心&#xff0c;建筑行业也在不断追求绿色、环保的设计与施工方案。气膜建筑&#xff0c;作为一种创新而轻盈的设计理念&#xff0c;正在走在绿色时尚的前沿。本文将探讨气膜建筑的独特之处以及其如何与环保理念相结合&#xff0c;领航着未来建筑…

Kubernetes(K8s)_15_CNI

Kubernetes&#xff08;K8s&#xff09;_15_CNI CNI网络模型UnderlayMAC VLANIP VLANDirect Route OverlayVXLAN CNI插件FlannelCalico CNI配置内置实现 CNI CNI(Container Network Interface): 实现容器网络连接的规范 Kubernetes将网络通信可分为: Pod内容器、Pod、Pod与Se…