分析下这段代码,有哪些问题和优化
class Counter {
private volatile int counter = 0;
public void incr() {
counter++;
}
public int get() {
return counter;
}
}
这段代码存在明显的并发安全问题,主要源于对volatile关键字的误用和原子性缺失:
⚠️ 核心问题分析
-
原子性缺失
counter++操作实际包含三个步骤:读取值 → 加1 → 写回值。**volatile仅保证可见性,无法保证复合操作的原子性**。当多线程并发执行时:- 线程A读取
counter=0 - 线程B读取
counter=0 - 双方各自加1后写回,最终结果变为
1而非预期的2(更新丢失)
- 线程A读取
-
volatile的局限性
volatile确保变量修改对所有线程立即可见,但无法解决多线程同时修改的竞争条件。对于自增操作,仍需额外同步机制。 -
长整型扩展问题
若未来需支持更大范围(如long),volatile long在32位系统上可能因非原子写导致数据撕裂(高位/低位更新分离)。
🛠️ 优化方案
✅ 方案1:使用原子类(推荐)
javaCopy Code
import java.util.concurrent.atomic.AtomicInteger;
class Counter {
private final AtomicInteger counter = new AtomicInteger(0);
public void incr() {
counter.incrementAndGet(); // 原子自增
}
public int get() {
return counter.get(); // 可见性由原子类内部保证
}
}
优势:
- 通过CAS(Compare-And-Swap)实现无锁并发,高性能
- 避免线程阻塞,适合高并发场景
✅ 方案2:同步锁控制
javaCopy Code
class Counter {
private int counter = 0;
public synchronized void incr() {
counter++; // 同步块内操作保证原子性
}
public int get() {
return counter; // 读操作无需同步(仅当incr同步时)
}
}
适用场景:
- 低频修改高频读取时效率较高
- 需注意锁粒度对性能的影响