happens-before

一、简介

        happens-before 规定了对共享变量的写操作对其它线程的读操作可见,它是可见性与有序性的一套规则总结,抛开以下 happens-before 规则,JMM 并不能保证一个线程对共享变量的写,对于其它线程对该共享变量的读可见,需要我们自己来控制。

二、案例展示

        1、线程解锁 m 之前对变量的写,对于接下来对 m 加锁的其它线程对该变量的读可见,即 使用 synchronized 保证了可见性。

	static int x;static Object m = new Object();new Thread(()->{synchronized(m) {x = 10;}},"t1").start();new Thread(()->{synchronized(m) {System.out.println(x);}},"t2").start();

        2、线程对 volatile 变量的写,对接下来其它线程对该变量的读可见

	volatile static int x;new Thread(()->{x = 10;},"t1").start();new Thread(()->{System.out.println(x);},"t2").start();

        3、线程 start 前对变量的写,对该线程开始后对该变量的读可见

	static int x;x = 10;new Thread(()->{System.out.println(x);},"t2").start();

        4、线程结束前对变量的写,对其它线程得知它结束后的读可见(比如其它线程调用 t1.isAlive() t1.join() 等待它结束)

	static int x;Thread t1 = new Thread(()->{x = 10;},"t1");t1.start();t1.join();System.out.println(x);

        5、线程 t1 打断 t2interrupt)前对变量的写,对于其他线程得知 t2 被打断后对变量的读可见(通过 t2.interrupted t2.isInterrupted

    static int x;public static void main(String[] args) {Thread t2 = new Thread(() -> {while (true) {if (Thread.currentThread().isInterrupted()) {System.out.println(x);break;}}}, "t2");t2.start();new Thread(() -> {sleep(1);x = 10;t2.interrupt();}, "t1").start();while (!t2.isInterrupted()) {Thread.yield();}System.out.println(x);}

        6、对变量默认值(0falsenull)的写,对其它线程对该变量的读可见,并且具有传递性,如果 x hb-> y 并且 y hb-> z 那么有 x hb-> z ,配合 volatile 的防指令重排,如下代码:

	volatile static int x;static int y;new Thread(()->{y = 10;x = 20;},"t1").start();new Thread(()->{// x=20 对 t2 可见, 同时 y=10 也对 t2 可见System.out.println(x);},"t2").start()

三、习题演练

3.1 balking 模式

        下面的代码只希望 doInit() 方法仅被调用一次,下面的实现是否有问题,为什么?

public class TestVolatile {volatile boolean initialized = false;void init() {if (initialized) {return;}doInit();initialized = true;}private void doInit() {}
}

        存在问题,假设 t1 t2 线程同时执行 init() 方法,当执行 if 判断的时候,都是 false,每个线程都会执行一次 doInit() 方法,虽然 initialized 使用了 volatile 修饰,但还是无法解决原子性问题,需要使用 synchronized 来解决。

3.2 线程安全单例习题

        单例模式有很多实现方法,饿汉、懒汉、静态内部类、枚举类,试分析每种实现下获取单例对象(即调用 getInstance)时的线程安全。

3.2.1 饿汉式

        饿汉式的特点是类加载就会导致该单实例对象被创建,如下代码:

// 问题1:为什么加 final?
// 回答:防止被子类继承,破坏单例// 问题2:如果实现了序列化接口, 还要做什么来防止反序列化破坏单例?
// 回答:需要在单例类中加一个返回值类型为 Object 的 readResovle() 方法,方法的返回值为单例对象。
//      在反序列的过程中,一旦发现 readResolve() 方法返回了对象,那么它就会采用你返回的这个对象。
public final class Singleton implements Serializable {// 问题3:为什么设置为私有? 是否能防止反射创建新的实例?// 回答:防止被其他类创建对象,不能防止反射来创建新的实例,因为反射可以获取构造器对象,还可以设置相关的属性,创建新的实例。private Singleton() {}// 问题4:这样初始化是否能保证单例对象创建时的线程安全?// 回答:可以保证,是 JVM 帮我们保证线程安全的private static final Singleton INSTANCE = new Singleton();// 问题5:为什么提供静态方法而不是直接将 INSTANCE 设置为 public, 说出你知道的理由// 回答:方法可以提供更好的封装性,内部可以实现懒惰的初始化。还可以支持泛型public static Singleton getInstance() {return INSTANCE;}public Object readResolve() {return INSTANCE;}
}

3.2.2 枚举

        可以使用枚举类实现单例。如下代码

// 问题1:枚举单例是如何限制实例个数的
// 回答:枚举类里面定义的枚举对象,定义了几个将来就有几个对象,它相当于是枚举类里面的静态成员变量。// 问题2:枚举单例在创建时是否有并发问题
// 回答:没有,因为静态成员变量是在类加载阶段完成的,不存在并发问题。// 问题3:枚举单例能否被反射破坏单例
// 回答:不能// 问题4:枚举单例能否被反序列化破坏单例
// 回答:不能// 问题5:枚举单例属于懒汉式还是饿汉式
// 回答:由于也是类加载阶段创建的,所以也属于饿汉式的// 问题6:枚举单例如果希望加入一些单例创建时的初始化逻辑该如何做
// 回答:加一些构造方法即可
enum Singleton {INSTANCE;
}

3.2.3 懒汉式

        懒汉式的特点是类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建,如下代码:

public final class Singleton {private Singleton() { }private static Singleton INSTANCE = null;// 问:分析这里的线程安全, 并说明有什么缺点?// 回答:是线程安全的,但是锁的范围有点大,每次调用都需要加锁,导致性能很低public static synchronized Singleton getInstance() {if( INSTANCE != null ){return INSTANCE;}INSTANCE = new Singleton();return INSTANCE;}
}

3.2.4 双重锁检查

        如下代码:

public final class Singleton {private Singleton() { }// 问题1:解释为什么要加 volatile ?// 回答:因为 synchronized 里面构造方法的指令和赋值的指令会重排序,加上 volatile 可以防止指令重排序private static volatile Singleton INSTANCE = null;// 问题2:对比实现3, 说出这样做的意义// 回答:这种方式只有第一次调用时会调用同步代码块,后面的调用直接返回了,提高了性能public static Singleton getInstance() {if (INSTANCE != null) {return INSTANCE;}synchronized (Singleton.class) {// 问题3:为什么还要在这里加为空判断, 之前不是判断过了吗// 回答:是为了防止第一次并发访问时单例对象不要被重复创建if (INSTANCE != null) { // t2return INSTANCE;}INSTANCE = new Singleton();return INSTANCE;}}
}

3.2.5 静态内部类

        如下代码:

public final class Singleton {private Singleton() { }// 问题1:属于懒汉式还是饿汉式// 回答:是懒汉式的,只有当用到的时候,才会对 LazyHolder 类进行加载,对里面的静态变量进行初始化private static class LazyHolder {static final Singleton INSTANCE = new Singleton();}// 问题2:在创建时是否有并发问题// 回答:不会存在线程安全问题。public static Singleton getInstance() {return LazyHolder.INSTANCE;}
}

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

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

相关文章

软件著作权申请教程(超详细)(2024新版)软著申请

目录 一、注册账号与实名登记 二、材料准备 三、申请步骤 1.办理身份 2.软件申请信息 3.软件开发信息 4.软件功能与特点 5.填报完成 一、注册账号与实名登记 首先我们需要在官网里面注册一个账号,并且完成实名认证,一般是注册【个人】的身份。中…

网安小贴士(17)认证技术原理应用

前言 认证技术原理及其应用是信息安全领域的重要组成部分,涉及多个方面,包括认证概念、认证依据、认证机制、认证类型以及具体的认证技术方法等。以下是对认证技术原理及应用的详细阐述: 一、认证概述 1. 认证概念 认证是一个实体向另一个实…

Langchain 对pdf,word,txt等不同文件的加载解析

项目中遇到各种数据资源想要加载近langchain构建本地知识ai系统,怎么加载对应的文件格式呢,一起研究下 引入Langchain from langchain.document_loaders import UnstructuredWordDocumentLoader,PyPDFium2Loader,DirectoryLoader,PyPDFLoader,TextLoad…

llama 2 改进之 RMSNorm

RMSNorm 论文:https://openreview.net/pdf?idSygkZ3MTJE Github:https://github.com/bzhangGo/rmsnorm?tabreadme-ov-file 论文假设LayerNorm中的重新居中不变性是可有可无的,并提出了均方根层归一化(RMSNorm)。RMSNorm根据均方根(RMS)将…

redis缓存击穿和缓存穿透的封装、缓存更新的CacheAside方案、数据预热

redis缓存击穿和缓存穿透的封装 一、首先是互斥锁二、封装为工具类三、调用四、数据预热五、缓存更新的CacheAside方案 (来源黑马redis) 一、首先是互斥锁 //拿到锁private boolean tryLock(String key) {Boolean flag stringRedisTemplate.opsForValue…

降低芯片流片风险的几种方法

[TOC] #说明 该文章仅科普下各方法是如何降低流片失败的可能性的。 #1. UVM方法学 1. uvm方法学的主要思想是通过用其它高级语言(python、c等)编写参考模型(REF)实现DUT设计相同功能。再使用uvm的一系列验证组件将相同的激励给…

每天一个数据分析题(四百三十六)- 正态分布

X为服从正态分布的随机变量N(2, 9), 如果P(X>c)P(X<c), 则c的值为&#xff08;&#xff09; A. 3 B. 2 C. 9 D. 2/3 数据分析认证考试介绍&#xff1a;点击进入 题目来源于CDA模拟题库 点击此处获取答案 数据分析专项练习题库 内容涵盖Python&#xff0c;SQL&…

用ssh tunnel的方式设置 AWS DocumentDB 公网访问

AWS DocumentDB的设定是只允许VPC内进行访问的&#xff0c;同时官方文档给了步骤&#xff0c;通过ssh tunnel的方式&#xff0c;可以从公网&#xff0c;或者从VPC外的网络&#xff0c;对DocumentDB进行访问。 我阅读了AWS官方文档并测试了这个步骤&#xff0c;如下是详细的步骤…

解决npm install(‘proxy‘ config is set properly. See: ‘npm help config‘)失败问题

摘要 重装电脑系统后&#xff0c;使用npm install初始化项目依赖失败了&#xff0c;错误提示&#xff1a;‘proxy’ config is set properly…&#xff0c;具体的错误提示如下图所示&#xff1a; 解决方案 经过报错信息查询解决办法&#xff0c;最终找到了两个比较好的方案&a…

HTTP协议、Wireshark抓包工具、json解析、天气爬虫

HTTP超文本传输协议 HTTP&#xff08;Hyper Text Transfer Protocol&#xff09;&#xff1a; 全称超文本传输协议&#xff0c;是用于从万维网&#xff08;WWW:World Wide Web &#xff09;服务器传输超文本到本地浏览器的传送协议。 HTTP 协议的重要特点&#xff1a; 一发一收…

Transformer中的自注意力是怎么实现的?

在Transformer模型中&#xff0c;自注意力&#xff08;Self-Attention&#xff09;是核心组件&#xff0c;用于捕捉输入序列中不同位置之间的关系。自注意力机制通过计算每个标记与其他所有标记之间的注意力权重&#xff0c;然后根据这些权重对输入序列进行加权求和&#xff0c…

JVM:MAT内存泄漏检测原理

文章目录 一、介绍 一、介绍 MAT提供了称为支配树&#xff08;Dominator Tree&#xff09;的对象图。支配树展示的是对象实例间的支配关系。在对象引用图中&#xff0c;所有指向对象B的路径都经过对象A&#xff0c;则认为对象A支配对象B。 支配树中对象本身占用的空间称之为…

Spire.PDF for .NET【文档操作】演示:如何在 C# 中切换 PDF 层的可见性

我们已经演示了如何使用 Spire.PDF在 C# 中向 PDF 文件添加多个图层以及在 PDF 中删除图层。我们还可以在 Spire.PDF 的帮助下在创建新页面图层时切换 PDF 图层的可见性。在本节中&#xff0c;我们将演示如何在 C# 中切换新 PDF 文档中图层的可见性。 Spire.PDF for .NET 是一…

【LabVIEW作业篇 - 1】:中途停止for和while循环

文章目录 for循环while循环如何使用帮助 for循环 在程序框图中&#xff0c;创建for循环结构&#xff0c;选择for循环&#xff0c;鼠标右键-条件接线端&#xff0c;即出现像while循环中的小红圆心&#xff0c;其作用与while循环相同。 运行结果如下。&#xff08;若随机数>…

分布式搜索引擎ES-Elasticsearch进阶

1.head与postman基于索引的操作 引入概念&#xff1a; 集群健康&#xff1a; green 所有的主分片和副本分片都正常运行。你的集群是100%可用 yellow 所有的主分片都正常运行&#xff0c;但不是所有的副本分片都正常运行。 red 有主分片没能正常运行。 查询es集群健康状态&…

ExoPlayer架构详解与源码分析(15)——Renderer

系列文章目录 ExoPlayer架构详解与源码分析&#xff08;1&#xff09;——前言 ExoPlayer架构详解与源码分析&#xff08;2&#xff09;——Player ExoPlayer架构详解与源码分析&#xff08;3&#xff09;——Timeline ExoPlayer架构详解与源码分析&#xff08;4&#xff09;—…

Pytest+selenium UI自动化测试实战实例

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 今天来说说pytest吧&#xff0c;经过几周的时间学习&#xff0c;有收获也有疑惑&#xff0c;总之…

【Python数据分析】数据分析三剑客:NumPy、SciPy、Matplotlib中常用操作汇总

文章目录 NumPy常见操作汇总SciPy常见操作汇总Matplotlib常见操作汇总官方文档链接NumPy常见操作汇总 在Python的NumPy库中,有许多常用的知识点,这里列出了一些核心功能和常见操作: 类别函数或特性描述基础操作np.array创建数组np.shape获取数组形状np.dtype查看数组数据类…

适用于618/7xx芯片平台 AT开发 远程FOTA升级指南教程

简介 AT版本的远程升级主要是对AT固件版本进行升级&#xff0c;实际方式为通过合宙官方IOT平台升级或者使用自己搭建的服务器进行升级服务。 该文档教程流程适用于 618/716S/718P 芯片平台的Cat.1模块 合宙IOT平台配置 升级日志 —— 如何查看 升级日志 —— 响应码列表 响应…

网络安全相关竞赛比赛

赛事日历&#xff08;包含全国所有网络安全竞赛&#xff09; https://datacon.qianxin.com/competition/competitions https://www.ichunqiu.com/competition/all 全国网络安全竞赛 名称链接全国大学生信息安全竞赛http://www.ciscn.cn/信息安全与对抗技术竞赛&#xff08;In…