原子类介绍
- java.util.concurrent.atomic
- java并发包下的类,用于多线程情况下保证线程安全的
API
- 基本类型原子类
- AtomicInteger
- 数组类型原子类
- AtomicIntegerArray
- 引用类型原子类
- AtomicReference
- 对象的属性修改原子类
- AtomicIntegerFieldUpdate
- 原子操作增强类
- LongAdder
- LongAccumulator
原子类高并发场景下效率对比
- LongAccumulator > LongAdder > AtomicInteger > synchronized
- 代码
class Number { int number = 0; // synchronized public synchronized void clickBySynchronized(){ number ++; } // AtomicInteger AtomicInteger atomicInteger = new AtomicInteger(0); public void clickAtomic(){ atomicInteger.incrementAndGet(); } // LongAdder LongAdder longAdder = new LongAdder(); public void clickLongAdder(){ longAdder.increment(); } // LongAccumulator LongAccumulator longAccumulator = new LongAccumulator((x, y) -> x + y, 0); public void clickLongAccumulator(){ longAccumulator.accumulate(1); } } /** * 50个线程,每个线程点赞100万次 性能对比 * * result * * synchronized 6361毫秒 * atomic 898毫秒 * longAdder 187毫秒 * longAccumulator 172毫秒 * */ public class 点赞量统计性能对比 { private static final int _w = 10000; private static final int size = 100; public static void main(String[] args) { Number number = new Number(); CountDownLatch countDownLatch = new CountDownLatch(size); long startTime = System.currentTimeMillis(); for (int i = 1;i <= size;i++){ new Thread(() -> { for (int k = 0;k < _w * 100;k++){ number.clickLongAdder(); } countDownLatch.countDown(); }).start(); } try { countDownLatch.await(); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("result: " + number.number); long endTime = System.currentTimeMillis(); System.out.println("时间:" + (endTime - startTime) + "毫秒"); } }
- 代码
LongAdder底层原理
-
LongAdder在无竞争的情况下,跟AtomicLong一样,对同一个base进行操作,当出现竞争关系是采用 化整为零分散热点的做法,用空间换时间,用一个数组cells,将value拆分成进入cells数组. 多个线程需要同时对value进行操作时,对线程id进行hash得到hash值,再根据hash值映射到这个数组cells的某个下标,再对下标所对应的值进行自增操作. 当所有线程操作完毕,将数组cells 和base 都加起来作为 最终结果
-
源码分析 add方法
public void add(long x) { Cell[] as; long b, v; int m; Cell a; if ((as = cells) != null || !casBase(b = base, b + x)) { boolean uncontended = true; if (as == null || (m = as.length - 1) < 0 || (a = as[getProbe() & m]) == null || !(uncontended = a.cas(v = a.value, v + x))) longAccumulate(x, null, uncontended); } }
-
如果cells 数组为空,尝试用CAS更新base字段,成功则退出,反之更新base失败了,说明出现了线程竞争, uncontended为true,调用longAccumulate
-
如果cells数组 非空,且当前线程映射的槽位为空,uncontended为true,调用longAccumulate
-
如果cells数组 非空,且当前线程映射的槽位非空,CAS更新cell的值,成功则返回,否则uncontended设为false,调用longAccumulate
-
-
sum方法
- sum()会将所有cell数组中的value和base累加作为返回值
-
总结
- 核心思想就是将之前AtomicLong 中的value 的更新压力分散到多个value中去,从而降级更新热点
- LongAdder不是强一致性,是最终一致性