多线程(53)happens-before原则

happens-before原则是Java内存模型(JMM)的核心概念,用于确定程序中两个操作间的可见性和有序性。简而言之,如果一个操作A happens-before另一个操作B,那么JVM保证A操作的结果对B操作是可见的,且A操作在B之前发生。

happens-before规则详解

  1. 程序顺序规则:在同一个线程中,根据程序控制流,前面的操作happens-before于后续的操作。

    java 复制代码
    int a = 1; // A操作
    int b = 2; // B操作

    在同一线程内,这里A操作happens-before B操作。

  2. 监视器锁规则:对一个锁的解锁happens-before于随后对这个锁的加锁。

    java 复制代码
    synchronized(lock) {
        // ...操作A
    }
    // 另一个线程或时刻
    synchronized(lock) {
        // ...操作B
    }

    在这个例子中,操作A的解锁happens-before操作B的加锁。

  3. volatile变量规则:对一个volatile字段的写操作happens-before于之后对这个volatile字段的读操作。

    java 复制代码
    volatile boolean flag = false;
    
    // 线程A
    flag = true;
    
    // 线程B
    if(flag) {
        // ...操作
    }

    线程A中对flag的写操作happens-before线程B中对flag的读操作。

  4. 线程启动规则:Thread对象的start()方法happens-before此线程的每个后续动作。

    java 复制代码
    Thread t = new Thread(() -> {
        // ...操作B
    });
    // 操作A
    t.start();

    线程的启动(操作A)happens-before线程t中的任何操作(操作B)。

  5. 线程终止规则:线程中的所有操作happens-before对此线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值等方式检测到线程已经终止。

  6. 中断规则:对线程interrupt()的调用happens-before被中断线程的检测到中断事件。

  7. 传递性:如果操作A happens-before操作B,且操作B happens-before操作C,那么操作A happens-before操作C。

代码示例:volatile变量规则

考虑以下代码示例,演示volatile规则的应用:

java 复制代码
public class VolatileExample {
    private volatile boolean ready = false;
    private int number;

    private class ReaderThread extends Thread {
        public void run() {
            while (!ready) {
                Thread.yield();
            }
            System.out.println("The number is: " + number);
        }
    }

    public void write() {
        number = 42;
        ready = true;
    }

    public static void main(String[] args) {
        VolatileExample example = new VolatileExample();
        example.new ReaderThread().start();
        example.write();
    }
}

这个例子中,write方法先改变number变量的值,然后将ready标志设置为true。由于ready是volatile变量,根据volatile变量规则,写入ready的操作happens-before于读取ready的操作,这确保了当读线程看到ready为true时,number变量的值对读线程是可见的。

总结

happens-before原则是理解Java内存模型的关键,它为开发者提供了一种判断数据在多线程环境下是否能保持一致性和有序性的方法。通过遵守这些规则,开发者可以编写出更加健壮和线程安全的并发代码。

相关推荐
Tokenfree6 小时前
用户一句「忽略以上指令」,客服机器人就开始骂人:提示词注入的四类入口和四层防线
后端
Bazingga7 小时前
一次线上CPU 100%的问题排查
后端
AskHarries7 小时前
如果人生可以重新投胎一次,你有多大概率出生在富豪家庭?😂
后端
nice_lcj5207 小时前
ThreadLocal 入门:它是怎么隔离数据的、为什么会导致内存泄漏
java·开发语言·后端·面试·并发编程·内存泄漏·threadlocal
紧跟先前的步伐7 小时前
Go AI Agent 实战 28|Agent 的预算、超时与停止条件
开发语言·人工智能·后端·ai·golang
Hespethorn7 小时前
112 个 Valgrind 错误,1 个根因:C++ 多线程服务的关机顺序复盘
后端·架构
小兔子8 小时前
new Date('2024-01-01') 和 new Date('2024/01/01') 差在哪
后端
Oiiouui9 小时前
linux服务器部署Logto后端与对应前端的实现
linux·服务器·前端·后端
shenlongproxy9 小时前
代理IP故障演练怎么做:注入怎么分档、恢复怎么判定
后端
知识搬运临时工9 小时前
Kafka 发 1 GiB 数据,用户态 CPU 只花 0.016 秒,总耗时反而慢了 11%
后端·kafka