首页 > 其他分享 >atomic原子类

atomic原子类

时间:2023-04-08 14:36:13浏览次数:39  
标签:LongAdder cells 原子 线程 atomic 数组 void public

原子类介绍

  • 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不是强一致性,是最终一致性

标签:LongAdder,cells,原子,线程,atomic,数组,void,public
From: https://www.cnblogs.com/liyong888/p/17298508.html

相关文章

  • 学了这么久的高并发编程,连Java中的并发原子类都不知道?
    摘要:保证线程安全是Java并发编程必须要解决的重要问题,本文和大家聊聊Java中的并发原子类,看它如何确保多线程的数据一致性。本文分享自华为云社区《学了这么久的高并发编程,连Java中的并发原子类都不知道?这也太Low了吧》,作者:冰河。今天我们一起来聊聊Java中的并发原子类。在 j......
  • 【Java 并发】【八】【Atomic】【二】AtomicInteger、AtomicBoolean原理
    1 前言这节我们从AtomicInteger这个比较简单的原子类开始,来看看AtomicInteger的底层原理。2  实测样例对比线程安全性在说AtomicInteger的底层原理之前呢,我们先来看个例子感受下原子类:static修饰的共享变量,我们开启两个线程对共享变量进行10000次+1的操作2.1  Integer......
  • 【Java 并发】【八】【Atomic】【一】JUC下的Atomic原子类体系概览
    1 前言这节我们就开始看看Atomic原子类系列,JUC包下提供的原子类底层的实现原理基本都是差不多的,都是基于volatile和CAS操作来保证线程安全的,我们后续会着重分析几个类。2  概览我们看下JUC下边都有哪些原子类:看上面的图形,我们使用红色圈中的那些,就是我们要着重讨论的,一共......
  • 八种原子操作
    为了支持JMM,Java定义了8种原子操作(Action),用来控制主存与工作内存之间的交互:read 读取:作用于主内存,将共享变量从主内存传动到线程的工作内存中,供后面的load动作使......
  • Java 原子类
    Java内部提供了两种方式来解决线程安全问题,一种是加入synchronized关键字,另一种则是使用Lock锁。虽然说这两种方式都能解决掉线程安全的问题,但是在某些场景下会稍微有......
  • 事务ACID(原子性,一致性,隔离性,持久性)
            ......
  • CAS 是一种什么样的同步机制?多线程下为什么不使用 int 而使用 AtomicInteger?
    CompareAndSwap,比较交换。可以看到synchronized可以保证代码块原子性,很多时候会引起性能问题,volatile也是个不错的选择,但是volatile不能保证原子性,只能在某些场合下使......
  • 【并发编程十四】c++原子操作(2)——实现自旋锁
     【并发编程十四】c++原子操作(2)——实现自旋锁一、自旋锁简介二、使用自旋锁三、不使用自旋锁四、分析 简介在介绍完原子操作,我们这篇使用c++提供的原子操......
  • 【并发编程十三】c++原子操作(1)
     【并发编程十三】c++原子操作(1)一、改动序列1、改动序列2、预测执行二、原子操作及其类别1、原子操作2、非原子操作3、原子类型三、标准原子类型1、......
  • 通过随机数Random 和 redis的incr每次增加一的原子性来动态绑定队列
    通过随机数(1,4)和redis的incr每次增加一的原子性来动态绑定队列队列:3个;pod:40个:1.通过随机数Random().Next(1,4)轮询每次返回1,2,3来达到一个消费端服务POD每次......