Atomic原子类-3

简介: Atomic原子类-3

@TOC

  • 在Atomic原子类-1 和 Atomic原子类-2
  • 我们介绍了Atomic 的用法以及简单的底层实现,那么我们这片文章讲下Atomic 的累加器

Adder 累加器

  • 是jdk 1.8 中引入的,比较新的一个类
  • 高并发的情况下 LongAdder 比 AtomitLong 效率高,不过是空间换时间
  • 竞争激烈的时候,LongAdder把不同的线程对应到不同的cell上进行修改,降低了冲突的概率,是多段锁的理念,提高了并发性

测试 AtomicLong的 性能

package com.yxzapp.ready;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 演示高并发情况下LongAdder 比 AtomicLong
 * 性能好
 */
public class AtomicLongDemo {

    public static void main(String[] args) throws InterruptedException {
        AtomicLong atomicLong = new AtomicLong(0);
        //线程池开始时间
        long start = System.currentTimeMillis();
        ExecutorService executorService = Executors.newFixedThreadPool(20);
        for (int i = 0; i < 10000; i++) {
            executorService.submit(new Task(atomicLong));
        }
        //表示线程池执行完毕
        executorService.shutdown();
        while (!executorService.isTerminated()){

        }
        long end = System.currentTimeMillis();
        System.out.println(atomicLong.get());
        System.out.println("耗时"+(end -start));
    }


    public static class Task implements Runnable{

        private AtomicLong atomicLong;

        public Task(AtomicLong atomicLong) {
            this.atomicLong = atomicLong;
        }

        @Override
        public void run() {

            for (int i = 0; i < 10000; i++) {
                atomicLong.incrementAndGet();
            }
        }
    }
}

运行结果:
在这里插入图片描述


package com.yxzapp.ready;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

/**
 * 演示高并发情况下LongAdder 比 AtomicLong
 * 性能好
 */
public class LongAdderDemo {

    public static void main(String[] args) throws InterruptedException {
        LongAdder atomicLong = new LongAdder();
        //线程池开始时间
        long start = System.currentTimeMillis();
        ExecutorService executorService = Executors.newFixedThreadPool(20);
        for (int i = 0; i < 10000; i++) {
            executorService.submit(new Task(atomicLong));
        }
        //表示线程池执行完毕
        executorService.shutdown();
        while (!executorService.isTerminated()){

        }
        long end = System.currentTimeMillis();
        System.out.println(atomicLong.sum() );
        System.out.println("耗时"+(end -start));
    }


    public static class Task implements Runnable{

        private LongAdder longAdder;

        public Task(LongAdder longAdder) {
            this.longAdder = longAdder;
        }

        @Override
        public void run() {

            for (int i = 0; i < 10000; i++) {
                longAdder.increment();
            }
        }
    }
}
在这里插入代码片

运行结果
在这里插入图片描述
会发现Longadder 比 AtomicLong 快了好多

  • 他们内部实现有些不同,AtomicLong每次加法都需要同步,所以冲突的比较多,也就降低了效率
  • 而 Longadder,每个线程都有自己的计数器,仅用来线程内计数,不会和其他线程干扰
  • AtomicLong引入了分段锁的概念,内部有一个base变量 和 cell[] 数组共同参与计数
  • base变量:竞争不激烈,直接累加到该变量上
  • cell [] 数组: 竞争激烈,各个线程分累加到自己到cell[i] 卡槽中

Accumulator 累加器

  • Accumualtor 和 Adder 非常相似,Accumualtor就是更通用的版本Adder
package com.yxzapp.ready;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.LongAccumulator;
import java.util.stream.IntStream;

public class LongAccumulatorDemo {

    public static void main(String[] args) {
        LongAccumulator accumulator = new LongAccumulator((x,y)->x+y,0);
        ExecutorService executorService = Executors.newFixedThreadPool(8);
        IntStream.range(1,10).forEach(i->executorService.submit(()->accumulator.accumulate(i)));
        executorService.shutdown();
        while (!executorService.isTerminated())
        System.out.println(accumulator.getThenReset());
    }

    public class Task{
        private LongAccumulator accumulator;

        public Task(LongAccumulator accumulator) {
            this.accumulator = accumulator;
        }
    }
}

对比
在这里插入图片描述

相关文章
|
缓存 中间件 测试技术
SOME/IP协议实践指南:精选开发与测试工具解析
SOME/IP协议实践指南:精选开发与测试工具解析
765 0
|
8月前
|
人工智能 大数据 BI
DeepSeek-R1模型全栈开发与部署实战培训高级研修班
掌握DeepSeek-R1模型从本地部署到工业级落地的全栈技术能力,包括环境配置、模型微调、推理优化及AI Agent开发等核心环节,能够独立完成基于RTX 4090的模型全生命周期开发任务。通过真实场景案例与全链路项目实战,培养将大模型技术转化为教育、企业服务等垂直领域解决方案的能力,涵盖需求分析、性能调优及工程化部署等关键技能,满足学术研究与产业落地的双重需求。
194 0
|
数据采集 人工智能 自然语言处理
中科大联合华为诺亚提出Entropy Law,揭秘大模型性能、数据压缩率以及训练损失关系
【8月更文挑战第14天】中科大与华为联合提出的Entropy Law理论,揭示了大语言模型性能与数据压缩率及训练损失的关系,指出低压缩率和高数据一致性有利于提升模型效能。基于此,开发出ZIP数据选择算法,通过多阶段贪婪策略优选低冗余样本,有效提高了模型训练效率和性能,同时降低了计算成本。这一成果为优化大模型训练提供了新途径。论文详述请见链接:https://arxiv.org/pdf/2407.06645。
348 65
IntelliJ IDEA 解决控制台不能显示日志
IntelliJ IDEA 解决控制台不能显示日志
1614 0
|
IDE 开发工具
IDEA如何快速定位到当前打开文件所在的目录
【10月更文挑战第7天】在 IntelliJ IDEA 中,要快速定位当前文件的目录,可通过侧边栏或快捷键实现。在侧边栏的项目结构中,文件以层级结构显示,便于浏览;使用 `Alt + F1` 快捷键,选择 “Select in”-&gt; “Project View”,即可迅速定位文件所在目录,方便管理和导航。
5275 3
|
缓存 C++ Windows
Inno setup 脚本判断 Microsoft Visual C++ Redistributable 不同版本区别
Inno setup 脚本判断 Microsoft Visual C++ Redistributable 不同版本区别
|
前端开发 安全 Java
springboot统一验证码组件设计(一)
springboot统一验证码组件设计
498 1
springboot统一验证码组件设计(一)
|
虚拟化
VMware配置网络,虚拟机无法联网,ping百度不通,居然这样解决了!
VMware配置网络,虚拟机无法联网,ping百度不通,居然这样解决了!
3453 0
VMware配置网络,虚拟机无法联网,ping百度不通,居然这样解决了!
@Singleton和@ApplicationScoped的区别
在JakartaEE的CDI标准中@Singleton和@ApplicationScoped的区别
836 0