04-JUC--atomic

什么是原子类?有什么用?

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

6类原子类纵览

在这里插入图片描述

AtomicInteger常用方法

在这里插入图片描述
在这里插入图片描述

代码演示1

/**
 * @Description:演示AtomicInteger的基本用法,对比非原子类的线程安全问题,使用原子类之后,不需要加锁,也可以保证线程安全。
 */
public class AtomicIntegerDemo1  implements Runnable{
    
    
    private static final AtomicInteger atomicInteger = new AtomicInteger();

    public void incrementAtomic(){
    
    
        atomicInteger.getAndIncrement();
    }
    //普通变量
    private static volatile  int basicCount =0;

    public 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 = 10000; i > 0; i--) {
    
    
            incrementAtomic();
            incrementBasic();
        }
    }
}

从输出结果来看,普通变量无法保证线程安全。
在这里插入图片描述

在给普通变量的increment()加上synchronized也可以实现线程安全,但是效率较为低下。

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

在这里插入图片描述

AtomicArray

代码演示

/**
 * @Classname AtomicArrayDemo1
 * @Description 演示原子数组的使用方法
 * @Date 2021/2/16 9:09
 * @Created by YoungLiu
 */
public class AtomicArrayDemo1 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(1000);
        Increment increment = new Increment(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);
            threadsDecrementer[i].start();

            threadsIncrementer[i]=new Thread(increment);
            threadsIncrementer[i].start();
        }

        for (int i = 0; i < 100; i++) {
    
    
            threadsDecrementer[i].join();
            threadsIncrementer[i].join();
        }

        for(int i =0;i<atomicIntegerArray.length();i++){
    
    
            if(atomicIntegerArray.get(i)!=0){
    
    
                System.out.println("发现了非0值,错误的位置 "+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 Increment implements  Runnable{
    
    
    private AtomicIntegerArray  array;

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


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

AtomicReference引用类型原子类

在这里插入图片描述

代码演示

以spinLock的代码为示例

public class SpinLock {
    
    
    private AtomicReference<Thread> sign= new AtomicReference<>();

    public void lock(){
    
    
        //得到当前线程的引用
        Thread current = Thread.currentThread();
        while(!sign.compareAndSet(null,current)){
    
    
            System.out.println(Thread.currentThread().getName()+"本次尝试获取自旋锁失败");
        }
    }

    public void unlock(){
    
    
        Thread current = Thread.currentThread();
        sign.compareAndSet(current,null);
    }

    public static void main(String[] args) {
    
    
        SpinLock spinLock = new SpinLock();
        Runnable runnable = new Runnable() {
    
    
            @Override
            public void run() {
    
    
                System.out.println(Thread.currentThread().getName() + "开始尝试获取自旋锁");
                spinLock.lock();
                System.out.println(Thread.currentThread().getName() + "获取到了自旋锁");
                try {
    
    
                    Thread.sleep(300);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                } finally {
    
    
                    spinLock.unlock();
                    System.out.println(Thread.currentThread().getName()+"释放了自旋锁");
                }
            }
        };
        Thread t0 = new Thread(runnable);
        Thread t1 = new Thread(runnable);
        t0.start();
        t1.start();
    }
}

把普通变量升级为具有原子功能

代码演示

/**
 * @Classnam AtomicIntegerFieldUpdaterDemo
 * @Description:演示AtomicIntegerFieldUpdater用法
 * @Date 2021/2/16 9:31
 * @Created by YoungLiu
 */
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;
    }

    public static void main(String[] args) throws InterruptedException {
    
    
        AtomicIntegerFieldUpdaterDemo r = new AtomicIntegerFieldUpdaterDemo();
        tom = new Candidate();
        peter = new Candidate();
        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("upgrading tom:" + tom.score);
        System.out.println("normal peter:" + peter.score);
    }
}

从程序输出结果可以看到,升级后的变量,实现了原子性操作。

在这里插入图片描述

AtomicIntegerFieldUpdater的注意点

1.可见范围 — 不能操作private的变量
2. 不支持static变量

Adder累加器

在这里插入图片描述

代码演示

/**
 * @Classname AtomicLongDemo
 * @Description 演示高并发场景下,LongAdder比AtomicLong性能高
 * @Date 2021/2/16 10:09
 * @Created by YoungLiu
 */
public class AtomicLongDemo {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        AtomicLong counter = new AtomicLong(0);
        ExecutorService service = Executors.newFixedThreadPool(16);
        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();
            }
        }
    }
}

在这里插入图片描述

**
 * @Classname LongAdderDemo
 * @Description TODO
 * @Date 2021/2/16 10:15
 * @Created by YoungLiu
 */
public class LongAdderDemo {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        LongAdder counter = new LongAdder();
        ExecutorService service = Executors.newFixedThreadPool(20);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
    
    
            service.submit(new LongAdderDemo.Task(counter));
        }
        service.shutdown();
        while(!service.isTerminated()){
    
    
        }
        long end = System.currentTimeMillis();
        System.out.println(counter.sum());
        System.out.println("longAdder耗时:"+(end-start));
    }
    private 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();
            }
        }
    }
}

对比两个程序的输出,可以看出在高并发情况下,LongAdder的性能比AtomicLong要高。
在这里插入图片描述

源码解析

由于CPU有不同的core,每个core做完一次操作后,其他的core都要刷新一次它的缓存,这会造成资源浪费。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Accumulator累加器

在这里插入图片描述

代码演示

/**
 * @Classname LongAccmulatorDemo
 * @Description  演示LongAccumulator用法
 * @Date 2021/2/16 11:18
 * @Created by YoungLiu
 */
public class LongAccmulatorDemo {
    
    
    public static void main(String[] args) {
    
    
        //最开始这个0,是赋给x的
        LongAccumulator accumulator = new LongAccumulator((x, y) -> x + y, 0);
        ExecutorService service = Executors.newFixedThreadPool(8);
        IntStream.range(1,10).forEach(i-> service.submit(()->accumulator.accumulate(i)));
        accumulator.accumulate(1);
        service.shutdown();
        while(!service.isTerminated()){
    
    

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

猜你喜欢

转载自blog.csdn.net/qq_41729287/article/details/113843979