Java是怎么保证原子性,可见性

本文探讨了在Java中volatile变量和锁如何确保可见性和原子性。volatile变量通过强制JVM从主内存读取最新值来实现可见性,但无法保证操作的原子性。锁不仅确保可见性还通过内存一致性协议实现原子性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先来谈谈可见性:

(1)volatile 变量:实际的作用:告诉jvm,这个变量的值不能取cpu的cache中的,应为那个值可能已经过时了,从这个层面来讲,volatile已经实现了可见性,但是他并没有实现原子性,原子性说白了就是一堆代码要一起执行完,比如说x++,这个在jvm层面上是要几条语句。。。。

(2)锁:jvm自己实现了一套内存一致性协议,对于变量的读写是由顺序控制的,read,load,store的变量是一定会写入主存的,已经由jvm的内存一致性协议完成了数据的读取写入问题


再来谈谈原子性:

volatile:不能完全实现可见性,如果你的当前值以来与之前的值

锁:一定能实现原子性----》在多线程情况下是程序会被串行执行



### Java可见性原子性的解释 #### 可见性 可见性指的是当多个线程访问同一个共享变量时,一个线程对该变量所做的修改能够立即被其他线程看到。如果缺乏这种特性,不同线程可能基于过期的数据副本工作,从而引发不可预期的行为。 为了确保可见性Java 提供了几种方法: - **`volatile`关键字**:声明为 `volatile` 的变量具有特殊的内存语义,即每次读取该变量都会直接从主存中获取最新值而不是缓存中的旧值[^4]。 - **同步块 (`synchronized`) 和锁 (`Lock`)**:这些机制不仅提供了互斥控制还隐含着对内存屏障的支持,使得进入或退出监视器区域前后发生的任何更新都能及时传播给所有参与竞争条件的线程[^1]。 - **`final`字段**:一旦对象构建完成并赋给了某个 final 字段,则此后的读操作总是能看到完整的初始化状态。 ```java public class VisibilityExample { private static volatile boolean flag = false; public void setFlagTrue() { flag = true; } public boolean getFlag() { return flag; } } ``` #### 原子性 原子性意味着一系列的操作要么全部成功执行且对外表现为单一的整体动作;要么完全不发生。对于多核或多处理器环境下的并发程序来说,保持某些关键逻辑片段的原子性至关重要,因为这能防止因中途被打断而导致的状态混乱。 以下是几种常见的实现原子性的手段: - **内置锁定 (`synchronized`)**:通过加锁的方式强制让一段代码成为临界区,在同一时间仅有一个线程可以进入这段代码,以此达到保护内部复合操作的目的。 - **显示锁接口 (`Lock` 接口及其具体实现类如 ReentrantLock)** :相比传统的 `synchronized` 更灵活强大,支持更复杂的场景需求[^5]。 - **无锁算法 (Non-blocking algorithms),特别是 CAS(Compare And Swap)**:这是一种乐观锁策略,它尝试不断比较当前值与期望值是否相等,若相符就替换为目标新值,否则重试直到成功为止。这种方式不需要阻塞线程就能高效地完成一些简单的增删改查任务。 ```java import java.util.concurrent.atomic.AtomicInteger; public class AtomicityExample { private AtomicInteger counter = new AtomicInteger(); public int incrementAndGetCounterValue() { return counter.incrementAndGet(); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值