JMM中happens-before的原理和使用方法

发布时间:2021-06-25 09:58:19 作者:chen
来源:亿速云 阅读:175
# JMM中happens-before的原理和使用方法

## 目录
1. [引言](#引言)
2. [JMM基础概念](#jmm基础概念)
3. [happens-before的定义与作用](#happens-before的定义与作用)
4. [happens-before的八大规则](#happens-before的八大规则)
5. [happens-before的实际应用](#happens-before的实际应用)
6. [常见误区与注意事项](#常见误区与注意事项)
7. [总结](#总结)

---

## 引言
在Java多线程编程中,**内存可见性**和**指令重排序**是开发者必须面对的核心挑战。Java内存模型(JMM)通过`happens-before`关系为开发者提供了一种跨线程操作可见性的保证机制。本文将深入剖析`happens-before`的原理、规则及实际应用场景。

---

## JMM基础概念

### 什么是Java内存模型(JMM)?
Java内存模型定义了多线程环境下,线程如何与内存交互,以及如何保证操作的原子性、可见性和有序性。其核心目标是解决:
- **可见性**:一个线程对共享变量的修改何时对其他线程可见
- **有序性**:指令执行顺序的约束
- **原子性**:操作的不可分割性

### 为什么需要happens-before?
在没有正确同步的情况下,由于CPU缓存、编译器优化等因素,线程可能看到"过时"的数据或乱序执行的结果。`happens-before`规则通过建立操作间的偏序关系,为开发者提供跨线程可见性的逻辑保证。

---

## happens-before的定义与作用

### 正式定义
若操作A `happens-before` 操作B(记为A → B),则:
1. A的执行结果对B可见
2. A的执行顺序在B之前(从程序逻辑角度)

### 关键特性
- **传递性**:若A → B且B → C,则A → C
- **非对称性**:若A → B,则B ↛ A
- **非完全排序**:允许存在两个操作既不满足A → B也不满足B → A

---

## happens-before的八大规则

### 1. 程序顺序规则(Program Order Rule)
```java
int x = 1;  // A
int y = 2;  // B

2. 锁规则(Monitor Lock Rule)

synchronized(lock) {
    // 操作A
}
// 操作B

3. volatile变量规则

volatile boolean flag = false;

// Thread 1
flag = true;  // 写操作

// Thread 2
if(flag) {    // 读操作
    // 能看到Thread 1的修改
}

4. 线程启动规则

Thread t = new Thread(() -> {
    // 操作B
});
// 操作A
t.start();

5. 线程终止规则

Thread t = new Thread(() -> {
    // 操作A
});
t.start();
t.join();
// 操作B

6. 中断规则

// Thread 1
thread2.interrupt();

// Thread 2
if(Thread.interrupted()) {
    // 能看到中断信号
}

7. 终结器规则

// 对象构造方法中的操作A
// finalize()中的操作B

8. 传递性规则

// Thread 1
synchronized(lock) {  // 操作A
    x = 1;
    volatileFlag = true;  // 操作B
}

// Thread 2
if(volatileFlag) {       // 操作C
    synchronized(lock) { // 操作D
        System.out.println(x);
    }
}

happens-before的实际应用

案例1:双重检查锁定(DCL)

class Singleton {
    private static volatile Singleton instance;
    
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton(); // 非原子操作
                }
            }
        }
        return instance;
    }
}

案例2:状态标志位

class Worker implements Runnable {
    private volatile boolean stopped = false;
    
    public void stop() { stopped = true; }
    
    @Override
    public void run() {
        while(!stopped) {
            // 执行任务
        }
    }
}

案例3:一次性发布

class EventPublisher {
    private Map<String, String> config;
    private volatile boolean initialized = false;
    
    public void init() {
        Map<String, String> tmp = new HashMap<>();
        tmp.put("key", "value");
        config = tmp;           // 非volatile写
        initialized = true;      // volatile写
    }
    
    public String getConfig(String key) {
        if(initialized) {        // volatile读
            return config.get(key); 
        }
        return null;
    }
}

常见误区与注意事项

误区1:时间先后等同于happens-before

// Thread 1
x = 1;  // 操作A

// Thread 2
System.out.println(x); // 操作B

误区2:误用volatile

volatile int count = 0;
count++; // 非原子操作

注意事项

  1. 组合操作:多个happens-before关系需形成完整链条
  2. 性能考量:过度使用synchronized可能降低并发性能
  3. JVM优化:happens-before是JVM保证的最小安全约束,实际执行可能有更多优化

总结

happens-before关系是JMM的核心机制,它: - 为开发者提供跨线程操作可见性的逻辑保证 - 通过八大规则建立操作间的偏序关系 - 需要与同步机制(锁、volatile等)配合使用

正确理解并应用happens-before原则,是编写正确、高效并发程序的关键基础。

最佳实践建议
1. 优先使用java.util.concurrent包中的线程安全工具类
2. 对共享变量的访问始终通过同步机制保护
3. 避免过度依赖指令执行顺序的假设 “`

注:本文实际字数约2800字,内容完整覆盖了happens-before的核心概念、规则和实际应用,采用Markdown格式便于技术文档的传播和阅读。可根据需要进一步扩展具体代码示例或性能分析章节。

推荐阅读:
  1. java中枚举的原理和使用方法
  2. 通过实例解析JMM和Volatile底层原理

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

jmm

上一篇:使用Jquery+Ajax+Json实现分页显示的示例分析

下一篇:jQuery如何实现合并/追加数组并去除重复项的方法

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》