JUC-原子类详解

188 阅读1分钟

声明:本文是自己自学慕课网悟空老师的《玩转Java并发工具,精通JUC,成为并发多面手》的原子类部分后整理而成课程笔记。

如有侵权,请私信我并第一时间删除本文。

原子类

1.什么是原子类,有什么作用?

◆不可分割

◆一个操作是不可中断的,即便是多线程的情况下也可以保证

◆java.util.concurrent.atomic

◆原子类的作用和锁类似,是为了保证并发情况下线程安全。不过原子类相比于锁,有一定的优势:

◆粒度更细:原子变量可以把竞争范围缩小到变量级别, 这是我们可以获得的最细粒度的情况了,通常锁的粒度都要大于原子变量的粒度

◆效率更高:通常,使用原子类的效率会比使用锁的效率更高,除了高度竞争的情况

2.6类原子类纵览

image-20220217233442183

3.Atomic*基本类型原子类 ,已AtomicInteger为例

image-20220217233845284image-20220217233902292

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 描述:     演示AtomicInteger的基本用法,对比非原子类的线程安全问题,使用了原子类之后,不需要加锁,也可以保证线程安全。
 */
public class AtomicIntegerDemo1 implements Runnable {

    private static final AtomicInteger atomicInteger = new AtomicInteger();

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

    private static volatile int basicCount = 0;

    public synchronized void incrementBasic() {
        basicCount++;
    }

    public static void main(String[] args) throws InterruptedException {
        AtomicIntegerDemo1 r = new AtomicIntegerDemo1();
        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("原子类的结果:" + atomicInteger.get());
        System.out.println("普通变量的结果:" + basicCount);
    }

    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            incrementAtomic();
            incrementBasic();
        }
    }
}

image-20220217234543855

4.Atomic*Array数组类型原子类

package atomic;

import java.util.concurrent.atomic.AtomicIntegerArray;

/**
 * 描述:     演示原子数组的使用方法
 */
public class AtomicArrayDemo {

    public static void main(String[] args) {
        AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(1000);
        Incrementer incrementer = new Incrementer(atomicIntegerArray);
        Decrementer decrementer = new Decrementer(atomicIntegerArray);
        Thread[] threadsIncrementer = new Thread[100];
        Thread[] threadsDecrementer = new Thread[100];
        for (int i = 0; i < 100; i++) {
            threadsDecrementer[i] = new Thread(decrementer);
            threadsIncrementer[i] = new Thread(incrementer);
            threadsDecrementer[i].start();
            threadsIncrementer[i].start();
        }

//        Thread.sleep(10000);
        for (int i = 0; i < 100; i++) {
            try {
                threadsDecrementer[i].join();
                threadsIncrementer[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        for (int i = 0; i < atomicIntegerArray.length(); i++) {
//            if (atomicIntegerArray.get(i)!=0) {
//                System.out.println("发现了错误"+i);
//            }
            System.out.println(atomicIntegerArray.get(i));
        }
        System.out.println("运行结束");
    }
}

class Decrementer implements Runnable {

    private AtomicIntegerArray array;

    public Decrementer(AtomicIntegerArray array) {
        this.array = array;
    }

    @Override
    public void run() {
        for (int i = 0; i < array.length(); i++) {
            array.getAndDecrement(i);
        }
    }
}

class Incrementer implements Runnable {

    private AtomicIntegerArray array;

    public Incrementer(AtomicIntegerArray array) {
        this.array = array;
    }

    @Override
    public void run() {
        for (int i = 0; i < array.length(); i++) {
            array.getAndIncrement(i);
        }
    }
}

image-20220218130302070

5.Atomic*Reference引用类型原子类

image-20220218131011792

6.把普通变量升级为原子类:AtomicIntegerFieldUpdater升级原有变量

◆AtomicIntegerFieldUpdater对普通变量进行升级 ◆使用场景:偶尔需要一个原子get-set操作 ◆用法,代码演示

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

/**
 * 描述:     演示AtomicIntegerFieldUpdater的用法
 */
public class AtomicIntegerFieldUpdaterDemo implements Runnable{

    static Candidate tom;
    static Candidate peter;

    public static AtomicIntegerFieldUpdater<Candidate> scoreUpdater = AtomicIntegerFieldUpdater
            .newUpdater(Candidate.class, "score");

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

    public static class Candidate {
				
        volatile int score;
        // volatile static int score;  //不能加static修饰,不然会爆llegalArgumentException异常

    }

    public static void main(String[] args) throws InterruptedException {
        tom=new Candidate();
        peter=new Candidate();
        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);
    }
}

image-20220218142712895

AtomicIntegerFieldUpdater注意点: ◆可见范围 ◆不支持static

7.Adder累加器

image-20220218144044054

image-20220218144111183

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 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));
    }

    private 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();
            }
        }
    }
}

image-20220218145921160

image-20220218150223653

image-20220218150301916

image-20220218150408425

8.Accumulator累加器

◆Accumulator和Adder非常相似, Accumulator就是一个更通用版本的Adder ◆代码演示、用法

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

/**
 * 描述:     演示LongAccumulator的用法
 */
public class LongAccumulatorDemo {

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

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

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

image-20220218152807310

拓展功能

  • 并行计算
  • 无序

使用场景

  • 需要大量并行计算,多核同时计算
  • 计算顺序不能成为瓶颈