我们对Atomic包下的这些内容,了解多少?

大家好,我是方圆
我们来主要写写Atomic包下拔高的东西


1. 重新认识认识原子类

原子类的作用与锁类似,是为了保证并发情况下的线程安全,而且它的粒度更细效率更高


2. 原子类纵览

在这里插入图片描述


3. AtomicIntegerFieldUpdater

在我们需要对一个字段进行原子操作的时候可以用这个类来进行升级,这样它节省了空间也优化了性能。

3.1 代码演示

注意要用volatile修饰,但是不能用static修饰

public class AtomicIntegerFieldUpdateDemo implements Runnable{
    //TODO 注意字段需要被volatile修饰,但是不能是static修饰的
    private volatile int a = 0;
    private volatile int b = 0;

    //用法有点儿像反射
    private static final AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdateDemo> updater =
            AtomicIntegerFieldUpdater.newUpdater(AtomicIntegerFieldUpdateDemo.class,"a");

    public int getA() {
        return a;
    }

    public int getB() {
        return b;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            updater.getAndIncrement(this);
            b++;
        }
    }
}
class Test {
    public static void main(String[] args) throws InterruptedException {
        AtomicIntegerFieldUpdateDemo demo = new AtomicIntegerFieldUpdateDemo();
        new Thread(demo).start();
        new Thread(demo).start();
        TimeUnit.SECONDS.sleep(1);

        System.out.println("升级过的int " + demo.getA());
        System.out.println("普通的int " + demo.getB());
    }
}
  • 测试结果
    在这里插入图片描述
    在这里插入图片描述

4. Adder累加器

  • 它在JDK1.8被加入
  • 在高并发下LongAdder相比于AtomicLong效率更高,本质上是用空间换时间(后面我们会看一看源码)
  • LongAdder把不同的线程对应的不同的Cell上,它底层维护一个Cell数组,相当于是多段锁的概念,提高了并发的性能

4.1 LongAdder代码测试

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

public class LongAdderDemo implements Runnable{
    private LongAdder longAdder;

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


    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            longAdder.increment();
        }
    }
}
class TestLongAdder {
    public static void main(String[] args) {
        LongAdder adder = new LongAdder();
        ExecutorService threadPool = Executors.newFixedThreadPool(8);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            threadPool.submit(new LongAdderDemo(adder));
        }
        threadPool.shutdown();

        while(! threadPool.isTerminated()) {

        }
        long endTime = System.currentTimeMillis();

        System.out.println(adder.sum());
        System.out.println("耗时 " + (endTime - startTime) + "ms");
    }
}
  • 结果:
    在这里插入图片描述

4.2 AtomicLong代码测试

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

public class AtomicLongDemo implements Runnable{
    private AtomicLong atomicLong;

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

    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            atomicLong.incrementAndGet();
        }
    }
}

class TestAtomicDemo {
    public static void main(String[] args) {
        AtomicLong atomicLong = new AtomicLong();
        ExecutorService threadPool = Executors.newFixedThreadPool(8);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            threadPool.submit(new AtomicLongDemo(atomicLong));
        }
        threadPool.shutdown();
        while (! threadPool.isTerminated()) {

        }
        long endTime = System.currentTimeMillis();
        System.out.println(atomicLong.get());
        System.out.println("耗时 " + (endTime - startTime) + "ms");

    }
}
  • 结果
    在这里插入图片描述

4.3 总结

我们可以发现,在高并发下,LongAdder有着更好的性能,主要是AtomicLong在每一次加法的时候,都要进行flush和refresh(JMM中,在自己的工作内存和主内存来回同步),导致很浪费资源

LongAdder的实现原来和AtomicLong是不同的,它并不需要进行同步,而是每个线程都有一个自己的计数器,没有一个线程会去进行计数统一
其中有两个重要的变量,Cell数组base基值,前者在高并发的时候使用,每个线程记录自己的累加值,后者在竞争不激烈的时候使用,直接加在base变量上
在这里插入图片描述
我们读一读sum方法的源码
在这里插入图片描述

在低并发的情况下,AtomicLong和LongAdder有着几乎一样的性能,不过当并发提高的时候,LongAdder的吞吐量很大,但是要耗费更多的空间,本质上就是用空间换时间;另一方面LongAdder没有提供CAS方法,这是它相比于AtomicLong的不足,LongAdder更适合的是统计求和和计数的场景


5. Accumulator累加器

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

public class AccumulatorDemo {
    public static void main(String[] args) {
        LongAccumulator accumulator = new LongAccumulator((x,y) -> 2 * x + y,1);
        ExecutorService threadPool = Executors.newFixedThreadPool(8);
        IntStream.range(1,3).forEach(i -> threadPool.submit(() -> accumulator.accumulate(i)));

        threadPool.shutdown();
        while(! threadPool.isTerminated()) {

        }

        System.out.println(accumulator.getThenReset());
    }
}

在这里插入图片描述
它相当于是对LongAdder的升级,我们能指定计算公式,它的底层同样也维护了Cell数组和base基值,能够进行多线程的计算


加油儿!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

方圆想当图灵

嘿嘿,小赏就行,不赏俺也不争你

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值