Java 并发中的原子类
1. 为什么需要原子类
多线程环境下,有个常见问题:
publicclassCounter{privateintcount=0;publicvoidincrement(){count++;}}count++看似一行代码,实际分三步:
- 读取 count 的值
- 加 1
- 写回 count
多线程下可能发生:
线程A:读取 count=0 线程B:读取 count=0 线程A:count=1,写回 线程B:count=1,写回 // 线程A的结果被覆盖了最终 count=1,但实际应该等于 2。
2. 解决办法
synchronized 加锁
publicsynchronizedvoidincrement(){count++;}缺点:性能差,每次只能一个线程进入。
原子类
privateAtomicIntegercount=newAtomicInteger(0);publicvoidincrement(){count.incrementAndGet();}一行搞定,性能比 synchronized 高很多。
3. 常用原子类
AtomicInteger
AtomicIntegercount=newAtomicInteger(0);// 加1count.incrementAndGet();// ++icount.getAndIncrement();// i++// 减1count.decrementAndGet();// --icount.getAndDecrement();// i--// 加任意值count.addAndGet(5);// 获取值intvalue=count.get();// 设置值count.set(100);// CAS 操作count.compareAndSet(100,200);// 如果当前值是100,则设置为200AtomicLong
和 AtomicInteger 用法一样,只是类型不同:
AtomicLongcount=newAtomicLong(0);count.incrementAndGet();AtomicBoolean
AtomicBooleanflag=newAtomicBoolean(false);// 设为 trueflag.set(true);// CAS 操作flag.compareAndSet(false,true);AtomicReference
用来原子更新对象:
AtomicReference<User>userRef=newAtomicReference<>();Useruser1=newUser("张三",20);Useruser2=newUser("李四",25);userRef.set(user1);userRef.compareAndSet(user1,user2);// 如果当前是 user1,则改为 user24. 数组原子类
// 数组中某个元素原子操作AtomicIntegerArrayarr=newAtomicIntegerArray(newint[]{1,2,3});arr.getAndAdd(0,10);// 第一个元素加10intvalue=arr.get(0);// 获取第一个元素5. 累加器
jdk8 新增的,比 AtomicInteger 性能更高,专门用于累加场景:
LongAddercount=newLongAdder();count.add(1);count.increment();longvalue=count.sum();内部原理是把一个值拆成多个 Cell,减少竞争。适合高并发场景下的累加。
// AtomicInteger vs LongAdder// 低并发:两者差不多// 高并发:LongAdder 性能更好6. 实战示例
计数器
publicclassPageViewCounter{privateAtomicIntegercount=newAtomicInteger(0);publicvoidaddView(){count.incrementAndGet();}publicintgetViews(){returncount.get();}}防止重复提交
publicclassSubmitService{privateAtomicBooleansubmitting=newAtomicBoolean(false);publicvoidsubmit(){// 如果已经在提交中,直接返回if(!submitting.compareAndSet(false,true)){return;}try{// 业务逻辑doSubmit();}finally{submitting.set(false);}}}配置更新
publicclassConfigHolder{privateAtomicReference<Config>configRef=newAtomicReference<>();publicvoidupdateConfig(ConfignewConfig){configRef.updateAndGet(old->newConfig);}publicConfiggetConfig(){returnconfigRef.get();}}7. 总结
| 类 | 用途 |
|---|---|
| AtomicInteger | 整数原子操作 |
| AtomicLong | 长整数原子操作 |
| AtomicBoolean | 布尔原子操作 |
| AtomicReference | 对象引用原子操作 |
| AtomicIntegerArray | 整数数组原子操作 |
| LongAdder | 高并发累加,比 AtomicLong 性能更好 |
什么时候用:
- 需要保证多线程安全地修改一个值时
- 简单计数、状态标记等场景
- 比 synchronized 性能更好
