Atomic的使用

AtomicInteger

  1. public static void main(String[] args) throws InterruptedException {
  2. AtomicInteger sum = new AtomicInteger(0);
  3. for (int i = 0; i < 10; i++) {
  4. new Thread(new Runnable() {
  5. @Override
  6. public void run() {
  7. for (int j = 0; j < 10000; j++) {
  8. //原子自增
  9. sum.incrementAndGet();
  10. }
  11. }
  12. }).start();
  13. }
  14. Thread.sleep(10000);
  15. System.out.println("sum:" + sum.get());
  16. }

截屏2022-03-15 21.23.14.png

AtomicIntegerArray,原子更新数组

  1. public static void main(String[] args) throws InterruptedException {
  2. int[] arr = {1, 2, 3, 4, 5};
  3. AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(arr);
  4. //把下标为2的值修改为10
  5. atomicIntegerArray.set(2, 10);
  6. System.out.println("当前下标2的值:" + atomicIntegerArray.get(2));
  7. //把下标为0的值加20
  8. atomicIntegerArray.getAndAdd(0,20);
  9. System.out.println(atomicIntegerArray);
  10. }

截屏2022-03-15 21.37.39.png

AtomicReference,原子更新引用类型

  1. public static void main(String[] args) throws InterruptedException {
  2. User user1 = new User(1, "haha1");
  3. User user2 = new User(2, "haha2");
  4. User user3 = new User(3, "haha3");
  5. AtomicReference<User> atomicReference = new AtomicReference<>(user1);
  6. //把user2赋值给Reference
  7. atomicReference.compareAndSet(user1, user2);
  8. System.out.println("当前Reference:" + atomicReference.get());
  9. //这里会设置失败,因为的Reference是user2
  10. atomicReference.compareAndSet(user1, user3);
  11. System.out.println("当前Reference:" + atomicReference.get());
  12. }

截屏2022-03-15 21.54.07.png

LongAdder/DoubleAdder

AtomicLong�是利用了CAS操作来提供并发性和原子性的,它的逻辑是采用自旋的方式不断更新目标值,直到更新成功。
截屏2022-03-15 22.44.58.png
但是,高并发环境下,N个线程同时进行自旋操作,会出现大量失败并不断自旋的情况,此时AtomicLong的自旋会成为瓶颈。

LongAdder引入的初衷——解决高并发环境下AtomicLong

例如AtomicLong中有个内部变量value保存着实际的long值,所有的操作都是针对该变量进行。也就是说,高并发环境下,value变量其实是一个热点,也就是N个线程竞争一个热点。
LongAdder的基本思路就是分散热点,将value值分散到一个数组中,不同线程会命中到数组的不同槽中,各个线程只对自己槽中的那个值进行CAS操作。这样热点就被分散了,冲突的概率就小很多。如果要获取真正的long值,只要将各个槽中的变量值累加返回。