并发编程的三要素是什么
1. 原子性(Atomicity)
定义:操作不可中断,要么全部执行成功,要么完全不执行,不会被其他线程干扰。
问题场景:多个线程对共享变量进行非原子操作(如
i++
)时,可能导致数据不一致。解决方案:
使用锁(如
synchronized
、ReentrantLock
)。利用原子类(如
AtomicInteger
)。通过事务或数据库的原子操作(在分布式系统中)。
2. 可见性(Visibility)
定义:一个线程修改共享变量后,其他线程能立即看到修改后的值。
问题场景:由于CPU缓存、指令重排序等优化,线程可能读取到过期的数据。
解决方案:
使用
volatile
关键字强制内存可见性。通过锁的释放和获取(锁会触发内存同步)。
显式调用
final
或不可变对象。
3. 有序性(Ordering)
定义:程序执行的顺序符合代码的先后顺序(避免指令重排序带来的问题)。
问题场景:编译器/处理器可能优化指令顺序(如单例模式中的双重检查锁问题)。
解决方案:
使用
volatile
禁止指令重排序。通过锁或内存屏障(如
synchronized
或Thread#join
)。遵循
Happens-Before
规则(如线程启动、终止规则等)。
三者的关系与保障
原子性关注操作的完整性,可见性关注数据的及时同步,有序性关注执行顺序的正确性。
实际开发中需综合运用同步工具(如
synchronized
同时保证三者,而volatile
仅保证可见性和有序性)。
示例代码
// 使用 volatile 保证可见性和有序性,但原子性需额外保障
private volatile int count = 0;// 使用 synchronized 保证三要素
public synchronized void increment() {count++; // 原子性+可见性+有序性
}
理解并应用这三要素,能有效避免竞态条件、死锁、数据脏读等并发问题。