JUC之atomic包

相关概念之原子性:
        原子性是指一个操作或多个操作要么全部执行,且执行的过程不会被任何因素打断,要么都不执行。

atomic包是java.util.concurrent下的一个专门为线程安全设计的java包,该包下包含多个原子操作类:

《JUC之atomic包》

atomic包下相对常用的类有:
        AtomicInteger、AtomicIntegerArray、AtomicBoolean、AtomicLong、AtomicLongArray

atomic包下的类使用场景:
        合适一些粒度比较小,如计数器这样的需求用起来较方便;如果是那些比较大比较复杂的场景,建议还是使用锁的方式。

 

声明:本人只挑了上述类中的三个类来测试说明

AtomicInteger

Integer与AtomicInteger安全性对比测试:

package com.aspire.demo;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Atomic包与CAS算法测试
 *
 * @author JustryDeng
 * @date 2018/10/25 16:14
 */
public class AtomicAndCASDemo {

    /** 线程数 */
    private static final Integer threadNum = 10000;

    /** Integer与AtomicInteger */
    private static Integer count = threadNum;
    private static AtomicInteger atomicInteger = new AtomicInteger(threadNum);

    /** 为了避免干扰,每个方法都使用自己对应的 */
    private static CountDownLatch countDownLatch1 = new CountDownLatch(threadNum);
    private static CountDownLatch countDownLatch2 = new CountDownLatch(threadNum);

    /** 为了避免干扰,每个方法都使用自己对应的 */
    private static CyclicBarrier cyclicBarrier1 = new CyclicBarrier(threadNum);
    private static CyclicBarrier cyclicBarrier2 = new CyclicBarrier(threadNum);

    /**
     * 多线程使用共享的Integer测试
     */
    private static void fa1() throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < threadNum; i++) {
            executorService.execute(() -> {
                try {
                    cyclicBarrier1.await();
                    count--;
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                } finally {
                    countDownLatch1.countDown();
                }
            });
        }
        executorService.shutdown();
        countDownLatch1.await();
        System.out.println("结果应为0, 本次运行结果count = " + count);
    }

    /**
     * 多线程使用共享的AtomicInteger测试
     */
    private static void fa2() throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < threadNum; i++) {
            executorService.execute(() -> {
                try {
                    cyclicBarrier2.await();
                    atomicInteger.getAndDecrement();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                } finally {
                    countDownLatch2.countDown();
                }
            });
        }
        executorService.shutdown();
        countDownLatch2.await();
        System.out.println("结果应为0, 本次运行结果atomicInteger = " + atomicInteger);
    }

    /**
     * 主函数
     */
    public static void main(String[] args) throws InterruptedException {
        fa1();
        System.out.println();
        fa2();
    }
}

运行主函数,(某次)控制台输出:

《JUC之atomic包》

说明:多次运行主函数,会发现fa1()输出的结果几乎总是大于0的错误的结果,fa2()输出的结果总是等于0的正确的结果,
          由此可见:AtomicInteger是线程安全的,Integer是非线程安全的

 

AtomicBoolean

AtomicBoolean说明:

        AtomicBoolean是一个线程安全的与Boolean对应的类。比较值得一说的是其public final boolean compareAndSet(boolean expect, boolean update)方法,该方法的功能是比较当前值atomicBoolean是否为期望值expect,如果是那么将更新值update赋给当前值atomicBoolean;如果当前值atomicBoolean不为期望值expect,那么直接返回false

如:atomicBoolean.compareAndSet(true, false)中,如果atomicBoolean为true,那么就把false值赋给atomicBoolean
     并返回true;如果atomicBoolean为false,那么就直接返回false。

注:AtomicBoolean是原子性的类,如:.compareAndSet(boolean expect, boolean update)方法的原子性就体现在:判断和
     赋值隶属于同一个原子操作;即:在其判断当前值atomicBoolean等于期望值expect后、赋值前,这中间是不会有其他
     线程对该atomicBoolean进行操作的。

注:更多方法可详见API文档。

Boolean与AtomicBoolean安全性测试:

package com.aspire.demo;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Atomic包与CAS算法测试
 *
 * @author JustryDeng
 * @date 2018/10/25 16:14
 */
public class AtomicAndCASDemo {

    /** 线程数 */
    private static final Integer threadNum = 10000;

    /** AtomicBoolean为保证多个.compareAndSet()的原子性,会用到锁 */
    private static final ReentrantLock lock = new ReentrantLock();

    /** Boolean与AtomicBoolean */
    private static Boolean aBoolean = true;
    private static AtomicBoolean atomicBoolean = new AtomicBoolean(true);

    /** 为了避免干扰,每个方法都使用自己对应的 */
    private static CountDownLatch countDownLatch3 = new CountDownLatch(threadNum);
    private static CountDownLatch countDownLatch4 = new CountDownLatch(threadNum);

    /** 为了避免干扰,每个方法都使用自己对应的 */
    private static CyclicBarrier cyclicBarrier3 = new CyclicBarrier(threadNum);
    private static CyclicBarrier cyclicBarrier4 = new CyclicBarrier(threadNum);


    /**
     * 多线程使用共享的Boolean测试
     */
    private static void fa3() throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < threadNum; i++) {
            executorService.execute(() -> {
                try {
                    cyclicBarrier3.await();
                    aBoolean = !aBoolean;
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                } finally {
                    countDownLatch3.countDown();
                }
            });
        }
        executorService.shutdown();
        countDownLatch3.await();
        System.out.println("结果应为true, 本次运行结果aBoolean = " + aBoolean);
    }

    /**
     * 多线程使用共享的AtomicBoolean测试
     */
    private static void fa4() throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < threadNum; i++) {

            executorService.execute(() -> {
                try {
                    cyclicBarrier4.await();
                    // 虽然.compareAndSet()本身是原子性的,但是多个.compareAndSet()就不是原子性的了
                    // 这里使用可重入锁,保证多个.compareAndSet()的原子性
                    lock.lock();
                    try {
                        boolean result = atomicBoolean.compareAndSet(true, false);
                        if(!result) {
                            atomicBoolean.compareAndSet(false, true);
                        }
                    } finally {
                        lock.unlock();
                    }

                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                } finally {
                    countDownLatch4.countDown();
                }
            });
        }
        executorService.shutdown();
        countDownLatch4.await();
        System.out.println("结果应为true, 本次运行结果atomicBoolean = " + atomicBoolean);
    }


    /**
     * 主函数
     */
    public static void main(String[] args) throws InterruptedException {
        fa3();
        System.out.println();
        fa4();
    }
}

运行主函数,(某次)控制台输出:

《JUC之atomic包》

说明:多次运行主函数,会发现fa4()总能输出true;而fa3()有时输出true,有时输出false;由此可见:AtomicBoolean是
         线程安全的,Boolean是非线程安全的

 

AtomicLongArray

Long[]与AtomicLongArray安全性测试:

package com.aspire.demo;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLongArray;

/**
 * Atomic包与CAS算法测试
 *
 * @author JustryDeng
 * @date 2018/10/25 16:14
 */
public class AtomicAndCASDemo {

    /** 线程数 */
    private static final Integer threadNum = 10000;

    /** Long[]与AtomicLongArray */
    private static Long[] longArray = new Long[1];
    private static AtomicLongArray atomicLongArray = new AtomicLongArray(1);

    /** 为了避免干扰,每个方法都使用自己对应的 */
    private static CountDownLatch countDownLatch5 = new CountDownLatch(threadNum);
    private static CountDownLatch countDownLatch6 = new CountDownLatch(threadNum);

    /** 为了避免干扰,每个方法都使用自己对应的 */
    private static CyclicBarrier cyclicBarrier5 = new CyclicBarrier(threadNum);
    private static CyclicBarrier cyclicBarrier6 = new CyclicBarrier(threadNum);

    /**
     * 多线程使用共享的Long[]测试
     */
    private static void fa5() throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < threadNum; i++) {
            final int index = i;
            executorService.execute(() -> {
                try {
                    cyclicBarrier5.await();
                    longArray[0] = longArray[0] + (long)index;
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                } finally {
                    countDownLatch5.countDown();
                }
            });
        }
        executorService.shutdown();
        countDownLatch5.await();
        System.out.println("结果应为49995000, 本次运行Long[]测试方法结果为" + longArray[0]);
    }

    /**
     * 多线程使用共享的AtomicLongArray测试
     */
    private static void fa6() throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < threadNum; i++) {
            final int index = i;
            executorService.execute(() -> {
                try {
                    cyclicBarrier6.await();
                    atomicLongArray.getAndAdd(0, index);
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                } finally {
                    countDownLatch6.countDown();
                }
            });
        }
        executorService.shutdown();
        countDownLatch6.await();
        System.out.println("结果应为49995000, 本次运行AtomicLongArray测试方法结果为" + atomicLongArray.get(0));
    }

    /**
     * 主函数
     */
    public static void main(String[] args) throws InterruptedException {
        longArray[0] =(long)0;
        atomicLongArray.set(0, 0);
        fa5();
        System.out.println();
        fa6();
    }
}

运行主函数,(某次)的输出结果为:

《JUC之atomic包》

说明:多次运行主函数,会发现fa5()输出的结果几乎总是错误的,fa6()输出的结果总是正确的,
         由此可见:AtomicLongArray是线程安全的,Long[]是非线程安全的

 

笔者将本人多线程一栏中博客涉及到的所有代码示例(Lock分开放在一个专门的项目、synchronized的代码附在该文章末尾),放在GIT上了(链接见本文末),这里先给出一个所涉及内容图:

《JUC之atomic包》

 

声明:本文是学习笔记,主要学习自以下视频
《JUC之atomic包》学习视频
           《Java多线程与并发实战视频课程》,齐毅 
《JUC之atomic包》多线程一栏所有测试示例代码,托管链接
           
https://github.com/JustryDeng/PublicRepository
《JUC之atomic包》如有不当之处,欢迎指正
《JUC之atomic包》本文已经被收录进《程序员成长笔记(三)》,笔者JustryDeng

    原文作者:JUC
    原文地址: https://blog.csdn.net/justry_deng/article/details/83413092
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞