原子变量与同步方法对比:能否实现相同线程安全效果?
核心结论
当然可以!用AtomicInteger替换原整数原语并移除synchronized关键字,完全能达到和原版本一致的线程安全效果,不会出现竞态条件,甚至在很多场景下性能表现更优。
为什么原synchronized版本能保证线程安全?
原代码里的increment()和decrement()方法被synchronized修饰,本质是通过独占锁机制实现线程安全:
- 同一时刻只有一个线程能进入这两个方法中的任意一个;
- 把
count++/count--这种非原子的「读-改-写」三步操作,打包成了一个原子性的整体,从根本上避免了多个线程同时操作导致的竞态条件。
原代码实现:
public class Counter { int count = 0; public synchronized void increment(){ count++; } public synchronized void decrement(){ count--; } }
AtomicInteger版本的线程安全原理
AtomicInteger是Java并发包java.util.concurrent.atomic提供的原子类,它靠**CAS(Compare-And-Swap)**这种无锁机制实现原子操作:
incrementAndGet()和decrementAndGet()方法本身就是原子性的,不需要依赖synchronized的独占锁;- CAS操作会先读取当前值,尝试将其更新为目标值,只有当当前值和预期值完全一致时才会更新成功,否则会自动重试直到操作完成,完美避免了「读-改-写」过程中的竞态条件。
替换后的代码实现:
public class Counter { AtomicInteger count = new AtomicInteger(); public void increment(){ count.incrementAndGet(); } public void decrement(){ count.decrementAndGet(); } }
两种实现的差异对比
虽然最终都能实现线程安全,但两者的实现机制和性能特点有明显区别:
- synchronized:属于独占锁机制,线程获取锁后会阻塞其他线程,高并发场景下可能带来上下文切换的开销;不过Java 6之后对锁做了大量优化(偏向锁、轻量级锁等),低并发场景下性能也很可观。
- AtomicInteger:基于无锁CAS实现,没有线程阻塞的开销,低到中并发场景下性能更优;但在极高并发场景下,CAS的重试次数会大幅增加,可能导致性能下降,这时
synchronized的表现反而更稳定。
总结
不管是用synchronized同步方法,还是用AtomicInteger的原子方法,都能有效避免竞态条件,实现线程安全的计数器功能。具体选哪种,可以根据业务的并发场景来决定。
内容的提问来源于stack exchange,提问作者Kuldeep
相关产品推荐
相关产品推荐

