原子类

原子类

  • 原子类
    • 不可分割
    • 一个操作是不可中断的,即使是多线程情况下也可以保证
    • java.util.concurrent.atomic
    • 原子类的作用和锁类似,是为了保证并发情况下线程安全、不过原子类比锁有一定得优势:
      1. 粒度更细:原子变量可以把竞争范围缩小到变量级别,这是我们可以获得的最细粒度的情况了,通常锁的粒度都要大于原子变量的粒度。
      2. 效率更高:通常,使用原子类的效率会比使用锁的效率更高,除了高度竞争的情况。

在这里插入图片描述

  • AtomicInteger常用方法:
    1. getAndDecrement() 获取当前值,并自减
    2. getAndAdd(int delta) 获取当前值,并加上预期的值
    3. compareAndSet(int expect,int update) 如果输入的数值等于预期值,则以原子方式将该值设置为输入值(update)。
    4. get() 获取当前的值。
    5. getAndSet(int newValue) 获取当前值,并设置新值
    6. getAndIncrement() 获取当前值,并自增
/**
 * 演示AtomicInteger的基本语法,对比非原子性的线程安全问题使用原子类后不需要加锁,也可以保证线程安全
 */
public class AtomicIntegerDemo1 implements Runnable {

    private static final AtomicInteger atomicInteger = new AtomicInteger();

    public void incrementAtomic() {
//        atomicInteger.getAndIncrement();
        atomicInteger.getAndAdd(-90);
    }

    private static volatile int basicCount = 0;

    public void incrementBasic() {
        basicCount++;
    }

    public static void main(String[] args) throws InterruptedException {
        AtomicIntegerDemo1 r = new AtomicIntegerDemo1();
        Thread thread1 = new Thread(r);
        Thread thread2 = new Thread(r);
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println("原子类的结果:"+atomicInteger.get());
        System.out.println("普通变量的结果:"+basicCount);
    }
    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            incrementAtomic();
            incrementBasic();
        }

    }
}
  • Atomic*Reference引用类型原子类
    • AtomicReference类的作用,和AtomicInteger并没有本质区别,AtomicInteger可以让一个整数保证原子性,AtomicReference可以让一个对象保证原子性,当然AtomicReference的功能明显比AtomicInteger强,因为对象包含很多属性,用法和AtomicInteger类似。
  • AtomicIntegerFieldUpdater
    • 实现了普通变量的原子操作
    • 可见范围(元素需要volatile修饰,如下面代码,score没有volatile修饰,会报java.lang.IllegalArgumentException: Must be volatile type)
    • 不支持static
/**
 * 演示AtomicIntegerFieldUpdater用法
 */
public class AtomicIntegerFieldUpdaterDemo implements Runnable{
    static Candicade tom;
    static Candicade peter;

    private static AtomicIntegerFieldUpdater<Candicade> scoreUpdate = AtomicIntegerFieldUpdater.newUpdater(Candicade.class,"score");

    @Override
    public void run() {
        for(int i = 0;i<10000;i++){
            peter.score ++;
            scoreUpdate.getAndIncrement(tom);
        }
    }

    public static class Candicade{
        volatile int score;
    }

    public static void main(String[] args) throws InterruptedException {
        tom = new Candicade();
        peter = new Candicade();

        AtomicIntegerFieldUpdaterDemo r = new AtomicIntegerFieldUpdaterDemo();
        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("普通变量"+peter.score);
        System.out.println("升级后的变量"+tom.score);
    }
}

* Adder累加器

  • java8引入的,相对比较新的一个类。
  • 高并发下LongAdder比AtomicLong效率高,不过本质都是空间换时间。
  • 竞争激烈的时候,LongAdder把不同线程对应到不同的Cell上进行修改,降低了冲突的概率,是多段锁的理念,提高了并发性。
    LongAdder代码演示,后面有AtomicLong代码演示
/**
 * 演示高并发情景下,LongAdder比AtomicLong性能好
 */
public class LongAdderDemo {

    public static void main(String[] args) {
        LongAdder counter = new LongAdder();
        ExecutorService service = Executors.newFixedThreadPool(20);
        long start = System.currentTimeMillis();
        for(int i = 0 ; i<10000 ; i++){
            service.submit(new Task(counter));
        }
        service.shutdown();
        while (!service.isTerminated()){

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

    public static class Task implements Runnable{
        private LongAdder counter;

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

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

AtomicLong代码演示

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

    public static void main(String[] args) {
        AtomicLong counter = new AtomicLong(0);
        ExecutorService service = Executors.newFixedThreadPool(20);
        long start = System.currentTimeMillis();
        for(int i = 0 ; i<10000 ; i++){
            service.submit(new Task(counter));
        }
        service.shutdown();
        while (!service.isTerminated()){

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

    public static class Task implements Runnable{
        private AtomicLong counter;

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

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

AtomicLong由于竞争激烈,每次加法,都要flush和refresh,导致很耗费资源。
在这里插入图片描述

  • LongAdder的改进和原理:
    1. 在内部,两个实现原理是不同的,上面的AtomicLong实现原理是,每一次加法都需要做同步,所以在高并发的时候就会导致冲突比较多,也就降低了效率。
    2. 而此时的LongAdder,每个线程会有自己的一个计数器,仅用来在自己线程内部计数,这样一来就不会和其他线程计数器干扰。
    3. 如下图所示,两个ctr各自加各自的,没有竞争关系,所以在加和的过程中,根本不需要同步机制,也不需要flush和refresh,这里也没有一个公共的counter来给所有线程统一计数。
    4. LongAdder引入了分段累加的概念,内部有一个base变量和一个Cell[]数组共同参与计数:
      • base变量 :竞争不激烈,直接累加到该变量上。
      • Cell[]数组:竞争激烈,各个线程分散累加到自己的槽Cell[i]中。
        在这里插入图片描述
    5. sum源码分析
      在这里插入图片描述
  • AtomicLong和LongAdder对比:
    1. 在低争用下,两个具有相似的特征。但是竞争激烈的情况下,LongAdder的预期吞吐量要高得多,但要消耗的空间也更多。
    2. LongAdder适合的场景是统计求和计数的场景,而AtomicLong还具有CAS方法。

* Accumulator累加器

  • Accumulator和Adder非常相似,Accumulator就是一个更通用版本的Adder。
/**
 * 演示LongAccumulator
 */
public class LongAccumulatorDemo {

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

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值