当前位置: 首页 > news >正文

JUC并发编程(五)volatile/可见性/原子性/有序性->JMM

目录

 一 可见性

二 原子性

三 有序性

四 volatile原理

1 如何保证可见性

2 如何保证有序性

3 无法解决指令交错(无法保证原子性)

4 双重检查锁(double-checked locking)

5 happens-before


总体概括

特性含义如何保障
原子性一个或多个操作要么全部执行成功,要么全部失败synchronizedAtomicInteger 等
可见性一个线程对共享变量的修改,其他线程能看到volatilesynchronizedfinal
有序性程序执行顺序与代码顺序一致volatilesynchronizedLock

 一 可见性

1 问题

代码展示:

package day01.neicun;public class example1 {static boolean flag = true;public static void main(String[] args) {Thread t1 = new Thread(() -> {while (flag) {}});t1.start();// 这里释放休眠,防止t1线程还未执行就被主线程给修改变量try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}flag = false;}
}

2 解决

  • 1 volatile易变关键字

它可以用来修饰成员变量和静态成员变量,可以避免线程从自己的工作缓存当中查找变量的值,必须到主存当中获取他的值,线程操作volatile变量都是直接操作主存。

线程不会再从缓存当中获取volatile的值,而是从主存当中获取,效率会有所下降,但是保证了共享变量在多个线程之间的可见性。

public class example1 {volatile static boolean flag = true;public static void main(String[] args) {Thread t1 = new Thread(() -> {while (flag) {}});t1.start();// 这里释放休眠,防止t1线程还未执行就被主线程给修改变量try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}flag = false;}
}
  • 2 使用synchroized

加锁(如 synchronizedReentrantLock)会强制线程从主内存中读取变量的最新值,而不是从本地缓存(工作内存)中读取。这是 Java 内存模型(JMM)保证可见性的核心机制之一。

package day01.neicun;public class example1 {static boolean flag = true;// 锁对象final static Object obj = new Object();public static void main(String[] args) {Thread t1 = new Thread(() -> {//这里会在执行完判断后将锁释放,那修改变量的同步代码块就可以运行了while (true) {synchronized (obj) {if (flag) {break;}}}});t1.start();// 这里释放休眠,防止t1线程还未执行就被主线程给修改变量try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (obj){flag = false;}}
}

二 原子性

机制原理适用场景特点
synchronized互斥锁需要保护临界区代码块或方法JVM内置,简单易用,可能阻塞
显式锁 (Lock)更灵活的互斥锁需要高级锁特性(可中断、公平等)更灵活,需手动释放锁
原子类CAS + volatile对单个变量进行原子操作无锁,高性能
不可变对象状态不可修改共享只读数据无同步开销,最安全

三 有序性

有序性是指:程序执行的顺序按照代码的先后顺序执行。

1 指令重排

指令重排(Instruction Reordering)是现代CPU和编译器为了提高程序执行效率而采用的关键优化技术。它通过重新排列指令的执行顺序来最大化利用CPU资源,但可能引发多线程环境下的可见性问题。

现代处理器会设计为一个时钟周期完成一条执行时间最长的CPU指令。

1 使用volatile的情况

public class ConcurrencyTest {int num = 0;volatile boolean ready = false;public void actor1(I_Result r) {if (ready) { // 读取 volatile 变量,确保看到最新的值r.r1 = num + num;} else {r.r1 = 1;}}public void actor2(I_Result r) {num = 2; // 写操作ready = true; // 写 volatile 变量,确保前面的操作已完成}
}

四 volatile原理

volatile 关键字的底层原理是 内存屏障(Memory Barriers) 机制。

volatile 解决的是 "一个线程写,其他线程读" 时的有序性和可见性问题,而解决 "多个线程同时写" 需要更强的同步机制。

  • 对volatile变量的写指令后会加入写屏障
  • 对volatile变量的读指令前会加入读屏障

总的来说写屏障保障之前的写and重排,读屏障保障之后的读and重排

1 如何保证可见性

  • 写屏障保证在该屏障之前的,对变量的改动都同步到主存当中。

  • 读屏障保证在该屏障之后对变量的读取,加载的是主存中的最新数据。

2 如何保证有序性

  • 写屏障会确保指令重排序时,不会将屏障之前的代码排在写屏障之后。

  • 读屏障会确保指令重排序时,不会将屏障之后的代码排在读屏障之前。

3 无法解决指令交错(无法保证原子性)

volatile 解决的是 "一个线程写,其他线程读" 时的有序性和可见性问题,而解决 "多个线程同时写" 需要更强的同步机制(结合锁机制确保)。

  • 写屏障仅仅是保证之后的读取能读取到最新的结果,但是不能保证读跑到他前面去。
  • 而有序性的保证也只是保证了本线程内相关代码不被重排序。

4 双重检查锁

双重检查锁(double-checked locking)的核心目的---以单例为例

1. 双重检查的作用

双重检查锁(Double-Checked Locking)的核心目的是:

  • 性能优化:第一次检查避免不必要的同步开销。
  • 线程安全:第二次检查确保在同步块内只有一个线程能创建实例。
代码示例
public final class Singleton {// 1. volatile 修饰的静态实例private static volatile Singleton instance;// 2. 私有构造函数private Singleton() {}// 3. 双重检查的获取实例方法public static Singleton getInstance() {if (instance == null) {                  // 第一次检查(无锁)synchronized (Singleton.class) {     // 同步块if (instance == null) {          // 第二次检查(有锁)instance = new Singleton();  // 创建实例}}}return instance;}
}

一些知识点

  1. final 修饰类的原因
    防止子类化破坏单例性,确保全局唯一性。

  2. 实例变量 private 的原因
    强制通过工厂方法访问,防止外部直接修改实例状态。(private为类内部)

  3. 实例变量 volatile 的原因
    禁止指令重排序(解决部分构造问题),保证跨线程可见性。

  4. 构造函数 private 的原因
    禁止外部实例化,确保单例控制权唯一。

  5. 两次 null 判断的原因
    首次检查(无锁)避免性能开销;二次检查(同步块内)防止重复创建。

  6. 类对象加锁的原因
    类锁保证全局唯一性,且独立于实例生命周期,避免死锁风险。

  7. 类的实现目的
    实现高性能线程安全单例:延迟加载、双重检查锁定、全局唯一实例访问。

破坏单例模式

1 反射方式

通过反射强行调用私有构造函数(setAccessible(true)),绕过单例的静态实例控制逻辑,直接创建新对象。

2 反序列化

反序列化时,ObjectInputStream 默认通过反射调用无参构造器新建对象,而非返回单例的静态实例。

普通方式解决

package day01.vola;import java.io.Serial;
import java.io.Serializable;public final class Singleton implements Serializable {// 1. volatile 修饰的静态实例private static volatile Singleton instance;// 2. 私有构造函数private Singleton() {// 防止反射破坏单例if (instance != null) {throw new RuntimeException("单例类禁止通过反射创建实例!");}}// 3. 双重检查的获取实例方法public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}// 4. 防止反序列化破坏单例@Serialprivate Object readResolve(){return instance;}
}

枚举方式解决

为何可以实现单例并解决反序列化和反射而导致的问题

  1. 实例数量固定:枚举在编译期确定所有实例,运行时无法创建新实例

  2. 类加载机制:枚举实例在首次访问时由 JVM 静态初始化(线程安全)

  3. JVM 底层保障

    • 禁止反射创建枚举实例(Constructor.newInstance() 直接抛出异常)

    • 特殊序列化机制(仅存储枚举名,反序列化通过 Enum.valueOf() 还原)

  4. 语法限制

    • 枚举构造器强制私有化

    • 不能显式实例化(编译器阻止 new 操作)

代码实现:

package day01.vola;public enum Single {// 唯一单例实例(名称可自定义)INSTANCE;// 单例状态字段(自动线程安全)private int requestCount = 0;// 单例业务方法public void handleRequest() {requestCount++;System.out.println("Handled request #" + requestCount);}// 可添加静态业务方法public static void warmUp() {System.out.println("Singleton initialized");}
}

静态内部类实现单例

5 happens-before

happens-before规定了对共享变量的写操作对其他线程的读操作可见,他是可见性与有序性的一套规则总结。

 八大规则

规则示例作用
程序顺序规则x=1; y=2; → x 先于 y单线程操作顺序保留
监视器锁规则解锁 → 后续加锁synchronized 可见性保证
volatile规则写 volatile → 后续读禁止重排序 + 跨线程可见
线程启动规则thread.start() → 线程内操作父线程配置对子线程可见
线程终止规则线程结束 → thread.join()子线程操作对父线程可见
传递性规则A→B 且 B→C ⇒ A→C跨操作链式可见
中断规则interrupt() → 检测到中断中断信号可靠传递
finalize规则构造结束 → finalize()对象完整构造后才回收

相关文章:

  • HBuilderX安装(uni-app和小程序开发)
  • 【大模型】大模型RAG(Retrieval-Augmented Generation)面试题合集
  • 第19节 Node.js Express 框架
  • 免费批量文件重命名工具
  • 两种Https正向代理的实现原理
  • 一.设计模式的基本概念
  • Python训练营打卡day46
  • 基于Scala实现Flink的三种基本时间窗口操作
  • 微软PowerBI考试 PL300-使用适用于 Power BI 的 Copilot 创建交互式报表
  • AI书签管理工具开发全记录(十五):TUI基本逻辑实现与数据展示
  • 理解 RAG_HYBRID_BM25_WEIGHT:打造更智能的混合检索增强生成系统
  • 使用 C++/OpenCV 创建动态流星雨特效 (实时动画)
  • PyTorch 中cumprod函数计算张量沿指定维度的累积乘积详解和代码示例
  • 常用函数库之 - std::function
  • 计算机操作系统(十五)死锁的概念与死锁的处理方法
  • 轮廓上距离最大的两个点
  • 温控加热电路【比较器输出作为MOS开关】
  • Python Copilot【代码辅助工具】 简介
  • C++修炼:C++11(二)
  • 鸿蒙仓颉语言开发实战教程:商城应用个人中心页面
  • 迅睿cms建站/爱站网关键字挖掘
  • 设计室内效果图设计/微博关键词排名优化
  • 凡科论坛网站制作/网站免费建站app
  • 西安网站优化排名案例/重庆seo代理
  • 大型网站建设动力无限/湖人队最新消息
  • 中国著名b2b电子商务网站/百度词条