分析并发编程之LongAdder原理

yizhihongxing

分析并发编程之LongAdder原理

LongAdder概述

Java中的LongAdder是一种专门针对高并发场景下的性能优化的累加器。在多线程并发情况下,普通的累加器或者AtomicLong等原子量可能会带来一定的性能问题,而LongAdder可以极大地提升并发场景下的性能表现。

LongAdder原理

内部数据结构

LongAdder内部是由一个Cells数组和一个base属性共同组成的。Base是一个普通的Long类型变量,用于存储低并发情况下的累加值。Cells是一个Cell数组,每一个Cell也是一个Long类型变量,并且各自独立存储,避免了高并发下的竞争。

累加操作

在进行累加操作时,会根据当前线程ID计算出需要操作的cell,然后直接操作对应的cell。如果当前线程需要操作的cell为空,则会尝试进行自旋操作,直到成功为止。

获取累加值

在获取累加值时,会将所有cell中的值都累加起来,再加上base的值,得到最终的结果。

示例说明

示例1

在高并发场景下,使用普通的AtomicLong来实现计数器,可能会带来性能瓶颈。可以使用LongAdder来替代,以达到更好的性能。

public class ConcurrentTest {
    private static final int THREADS_COUNT = 20;
    private static final int COUNT_NUM = 1000000;
    private static final AtomicLong atomicLong = new AtomicLong(0);
    private static final LongAdder longAdder = new LongAdder();

    public static void main(String[] args) throws InterruptedException {
        Thread[] atomicThreads = new Thread[THREADS_COUNT];
        Thread[] adderThreads = new Thread[THREADS_COUNT];
        for (int i = 0; i < THREADS_COUNT; i++) {
            atomicThreads[i] = new Thread(() -> {
                for (int j = 0; j < COUNT_NUM; j++) {
                    atomicLong.incrementAndGet();
                }
            });
            adderThreads[i] = new Thread(() -> {
                for (int j = 0; j < COUNT_NUM; j++) {
                    longAdder.increment();
                }
            });
        }

        long atomicStart = System.currentTimeMillis();
        for (Thread atomicThread : atomicThreads) {
            atomicThread.start();
        }
        for (Thread atomicThread : atomicThreads) {
            atomicThread.join();
        }
        long atomicEnd = System.currentTimeMillis();
        System.out.println("AtomicLong: " + atomicLong);
        System.out.println("Time(ms): " + (atomicEnd - atomicStart));

        long adderStart = System.currentTimeMillis();
        for (Thread adderThread : adderThreads) {
            adderThread.start();
        }
        for (Thread adderThread : adderThreads) {
            adderThread.join();
        }
        long adderEnd = System.currentTimeMillis();
        System.out.println("LongAdder: " + longAdder);
        System.out.println("Time(ms): " + (adderEnd - adderStart));
    }
}

运行结果:

AtomicLong: 20000000
Time(ms): 651
LongAdder: 20000000
Time(ms): 77

示例2

在多个线程并发写入AtomicLong对象时,性能会受到严重的影响。可以使用ThreadLocalRandom类和LongAdder来实现高效的并发累加。

public class ConcurrentTest2 {
    private static final int THREADS_COUNT = 20;
    private static final int COUNT_NUM = 1000000;
    private static final ThreadLocalRandom random = ThreadLocalRandom.current();
    private static final Map<Integer, LongAdder> map = new ConcurrentHashMap<>();

    public static void main(String[] args) throws InterruptedException {
        Thread[] threads = new Thread[THREADS_COUNT];
        for (int i = 0; i < THREADS_COUNT; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < COUNT_NUM; j++) {
                    int key = random.nextInt(THREADS_COUNT);
                    map.computeIfAbsent(key, k -> new LongAdder()).increment();
                }
            });
        }

        long start = System.currentTimeMillis();
        for (Thread thread : threads) {
            thread.start();
        }
        for (Thread thread : threads) {
            thread.join();
        }
        long end = System.currentTimeMillis();
        System.out.println("Time(ms): " + (end - start));
        System.out.println(map);
    }
}

运行结果:

Time(ms): 23
{0=100152, 2=99970, 3=100444, 4=100247, 5=99279, 6=99388, 7=99435, 9=101749, 10=99207, 11=99882, 12=100249, 13=101410, 14=100231, 15=100152, 16=99403, 17=99468, 18=100374, 19=101082}

总结

LongAdder是一种非常高效的累加器,在高并发场景下可以有效提升程序性能。在实际编码中,可以根据自己的实际情况选择性使用LongAdder来进行优化。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:分析并发编程之LongAdder原理 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • JavaScript使用Promise实现并发请求数限制

    JavaScript使用Promise实现并发请求数限制的攻略如下: 1. Promise简介 Promise是JavaScript中一种异步编程解决方案,可以让我们更好的处理异步调用,避免了异步回调带来的问题。 2. 并发请求数限制 当我们需要对一组URL同时发送请求时,如果请求的URL过多,可能会导致服务器压力过大,或者我们的客户端无法处理这么多请求。因…

    多线程 2023年5月17日
    00
  • mysql中insert并发问题(on DUPLICATE KEY UPDATE)

    MySQL中的INSERT操作是非常常见的操作,但是在高并发的情况下,INSERT操作可能会出现一些问题,这就是INSERT并发问题。具体来说,当多个用户同时向一个表中进行INSERT操作时,就会有并发问题出现,可能会导致数据错乱、重复插入等问题。为了解决这个问题,MySQL引入了一个非常有用的特性:ON DUPLICATE KEY UPDATE。 ON D…

    多线程 2023年5月17日
    00
  • Java多线程三种主要实现方式解析

    Java多线程三种主要实现方式解析 在Java中,多线程的实现方式有三种:继承Thread类、实现Runnable接口和实现Callable接口。本文将详细介绍这三种实现方式的使用方法及优缺点。 继承Thread类 第一种实现方式是继承Thread类,并重写其run()方法。这种方式的优点在于编写简单,易于理解。下面是示例代码: public class M…

    多线程 2023年5月17日
    00
  • PHP细数实现提高并发能力的方法

    PHP细数实现提高并发能力的方法 1. 使用多线程 在PHP中,使用多线程技术可以有效提高并发能力。多线程技术可以将程序的运行分为多个部分同时执行,从而最大限度地利用CPU资源。 PHP原生虽然不支持多线程,但可以使用扩展库来实现。目前比较常见的扩展库有pthreads和pcntl。 以下是一个使用pthreads扩展库实现多线程的示例: <?php …

    多线程 2023年5月16日
    00
  • 详解易语言启动多线程

    下面是详解易语言启动多线程的完整攻略。 什么是多线程 多线程是指一个进程中含有多个线程(Thread)并行执行的情况,不同的线程可以分别完成不同的任务。在单核CPU的情况下,多个线程只是在时间片之间切换,看起来是同时执行的。而在多核CPU的情况下,则可以真正实现多任务并行执行。 如何启动多线程 易语言中提供了一个系统函数CreateThread,可以用来创建…

    多线程 2023年5月17日
    00
  • java多线程之wait(),notify(),notifyAll()的详解分析

    Java多线程之wait(), notify(), notifyAll()的详解分析 在Java多线程编程中,wait(), notify(), notifyAll()是非常重要的方法。这三个方法都是用于线程间的协作,可以让线程在合适的时候等待或唤醒其他线程,实现高效的资源共享和数据交换。本文将详细介绍wait(), notify(), notifyAll(…

    多线程 2023年5月16日
    00
  • Python使用asyncio包处理并发详解

    当今网络服务越来越注重并发访问的处理,常见的异步框架有 gevent, twisted, tornado等,而作为一个优秀的异步框架,Python的asyncio更是备受关注。Asyncio 是 Python 3.4 新增的异步IO模块,它提供了基于协程的异步编程方式,使得异步编程更加易用、高效、可控。 下面我们来详细介绍Python中使用asyncio包进…

    多线程 2023年5月17日
    00
  • Java并发编程之阻塞队列(BlockingQueue)详解

    Java并发编程之阻塞队列(BlockingQueue)详解 什么是阻塞队列? 阻塞队列,顾名思义就是在队列的基础上加入了阻塞的特性。当队列满时,阻塞队列会自动阻塞写入线程,直到队列中有元素被移除,而当队列为空时,阻塞队列会自动阻塞读取线程,直到队列中有元素被添加。 Java中的阻塞队列是一个线程安全的队列,实现了如同锁的机制,可以保证多个线程同时访问是安全…

    多线程 2023年5月16日
    00
合作推广
合作推广
分享本页
返回顶部