Home 并发编程:Java 如何解决 可见性,有序性和原子性
Post
Cancel

并发编程:Java 如何解决 可见性,有序性和原子性

在 Java 并发编程中,可见性、有序性、原子性是并发错误的三大核心根源。 其中 JMM (Java内存模型)用来解决 可见性 和 有序性


一、如何解决 可见性问题

问题回顾:

  • 一个线程修改了共享变量,其他线程看不到(缓存没有刷新)。

🔧 Java 解决方式:

机制 说明
volatile 禁止线程缓存变量,修改立即写入主内存;读取强制从主内存读。 ✅轻量方式
synchronized 加锁会刷新工作内存,进入同步块前读取主内存,退出时写回主内存
final 构造函数安全发布(对象构造完成前不能被其他线程看到)
JMM 的 happens-before 规则 Java 的内存模型定义了一系列可见性保证规则

二、如何解决 有序性问题

问题回顾:

  • JVM 和 CPU 会重排序指令,导致多线程执行顺序不一致。

🔧 Java 解决方式:

机制 说明
volatile 禁止重排序(对读写操作的指令不会和前后的指令重排序)
synchronized 锁具备内存屏障效果,进入和退出同步块都包含“顺序约束”
happens-before 语义 JMM 规定了某些操作之间的“先发生于”关系,编译器/CPU 会保持顺序

📝 举例(重排序引发的问题):

1
2
3
4
5
6
7
8
9
10
11
int a = 0;
boolean flag = false;

Thread A:
    a = 1;
    flag = true; // 可能重排序到前面

Thread B:
    if (flag) {
        System.out.println(a); // 可能输出 0
    }

使用 volatile flag 可禁止重排序。


三、如何解决 原子性问题

问题回顾:

  • 多线程并发修改变量时,中间过程被打断,导致结果错误。

🔧 Java 解决方式:

机制 说明
synchronized 让某段代码在任意时刻只允许一个线程执行,从而保证操作的原子性
ReentrantLock 可替代 synchronized,有更强的功能(可中断、公平锁、tryLock)
AtomicInteger 等原子类 JDK 提供的原子操作类,底层基于 CAS,可高性能地支持线程安全的加减等操作
数据结构并发容器(如 ConcurrentHashMap 内部采用分段锁或CAS原语,支持高性能并发访问

总结

并发问题 典型现象 Java 解决机制
可见性 线程 A 修改变量,线程 B 看不到 volatilesynchronizedfinal、JMM happens-before
有序性 指令被重排序,行为反直觉 volatilesynchronized、JMM 顺序规则
原子性 多线程修改共享变量,结果错误 synchronizedLockAtomicXXX、并发容器

weixin.png

公众号名称:怪味Coding
微信扫码关注或搜索公众号名称
This post is licensed under CC BY 4.0 by the author.

并发编程:JDK7 和 JDK8 的 ConcurrentHashMap 锁实现方案

并发编程:Java 线程生命周期