Atomic原子类-3

  • 在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;
        }
    }
}

对比
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41977838/article/details/106603525