• 并发编程学习总结(二、AQS实现类总结)


    目录:

    • ReentrantLock
    • Semaphore
    • CountDownLatch
    • CyclicBarrier
    • ArrayBlockingQueue、LinkedBlockingQueue、DelayQueue
    • CopyOnWriteArrayList

    上一节吧AQS相关的知识点整理了下,这一节我来整理下AQS的一些实现类及JUC的工具包。

    ReentrantLock

    1、是什么:

    • ReentrantLock与synchronize都是可重入锁,它可以说是synchronize的一种扩展
    • synchronize是内置锁,加锁与解锁都是交由JVM来实现的,而ReentrantLock则是JUC提供的一种由客户端来控制的可重入锁,控制粒度由用户自行决定更加灵活

    2、实现原理:

    • 通过为每个锁关联一个请求计数器获得该锁的线程来实现,当计数器的值为0时表示该锁是未被占用的。
    • 当线程请求一个未被占用的锁时,计数器的值加1,此时线程就为获取到该锁的状态,再次请求获取此锁时计数器将递增;
    • 当此线程退出这个同步方法或代码块时,计数器将递减,直到计数器的值变为0时就表示锁已释放,其它线程才能获取该锁。
    • 基于AQS排它锁实现。

    Semaphore

    1、是什么:

    • Semaphore和ReentrantLock一样,也是对synchronize的扩展;
    • 不同的是ReentrantLock是锁粒度和灵活去的扩展,而Semaphore是对并发数量的扩展,控制线程的并发数量。

    2、实现原理:

    • 通过在Semaphore初始化的时候传入一个凭证,每当有一个线程获取到锁后就将凭证数量减1,释放锁后凭证数量加1;
    • 直到凭证数据小于等于0时就不再允许线程获取锁。
    • 基于AQS共享锁实现。

    CountDownLatch

    1、是什么:

    • 我们知道join()方法的作用是让一个线程执行完后再执行另一个线程,但你如果进一步了解它的话你就会知道join()方法控制的粒度比较大,它是以整个线程为单位的;也就是说join()只能在某线程执行完后才能执行另一个线程,如果我们有如下场景那join()就不能完成工作了:
    • 线程A和线程B分别都要执行两个动作,记为A1、A2、B1、B2,我需要在线程A执行完A1后就要执行线程B的B1、B2。
    • 如果遇到类似的场景就需要使用CountDownLatch来实现了,它是join()方法的扩展,可以更加细粒度的控制线程之间的执行问题;通过countDown()和await()来实现。

    2、实现原理:

    • 通过构造函数初始化一个内置的计数器,当计数器为0时会唤醒所有调用await()方法而被阻塞的线程
    • 一般情况下我们通过完成某个操作后来调用countDown()减少计数器的值,通过await()方法阻塞线程,让其执行完毕后再退出方法。
    • 基于AQS共享锁实现。

    CyclicBarrier

    1、是什么:

    • 循环栅栏,可以让所有线程都等待执行完后再继续做后续处理,与CountDownLatch非常类似,不同的是CountDownLatch是一次性的,而CyclicBarrier是可以循环使用的。
    • 可以说CyclicBarrier是CountDownLatch的扩展,是对CountDownLatch执行能力的扩展,可重复执行。

    2、实现原理:

    • 底层基于ReentrantLockCondition实现,定义了parties字段来表示栅栏数量,当parties满足特定条件后则唤醒线程,这是让所有线程都等待执行完后再继续做后续处理的实现原理。
    • 而重复使用的原理则是通过一个叫Generation的内部类中的broken来标记,每当调用await()方法是栅栏数就会减1,直到数量为0时就会唤醒在此之上的所有线程,并重置broken为false,这样就又可以继续使用栅栏了。

    ArrayBlockingQueue、LinkedBlockingQueue

    1、是什么:

    • ArrayBlockingQueue通过数组实现的线程安全的阻塞队列;LinkedBlockingQueue通过链表实现的线程安全的阻塞队列。
    • 用于在线程池中,运行线程数大于核心线程数时,将新加入的线程放到此阻塞队列中。

    2、实现原理:

    • 底层同样是基于ReentrantLock和Condition来实现,通过Condition notEmpty、Condition notFull来阻塞唤醒线程的获取、添加操作。

    DelayQueue

    1、是什么:

    • DelayQueue是一个支持延时获取元素无界阻塞队列,队列使用PriorityQueue来实现。
    • 队列中的元素必须实现Delayed接口,在创建元素时可以指定多久才能从队列中获取当前元素,只有在延迟期满时才能从队列中提取元素

    2、实现原理:

    • emmmmm,同样的还是基于ReentrantLock和Condition来实现,等时间到了唤醒线程获取值。

    CopyOnWriteArrayList

    1、是什么:

    • CopyOnWriteArrayList是一个写入时复制的集合,与其说它是一种新的数据结构还不如说它是一种设计思想。

    2、实现原理:

    • 当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后往新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器
    • 这时候会抛出来一个新的问题,也就是数据不一致的问题。如果写线程还没来得及写回内存,其他的线程就会读到了脏数据。
    • 这就是CopyOnWriteArrayList的思想和原理,就是拷贝一份写;所以使用条件也很局限,那就是在读多写少的情况下比较好。
  • 相关阅读:
    B/S架构
    RPC远程过程调用详解
    Ubuntu18.04安装MongoDB
    Python2.X SQLAlchemy @@tx_isolation警告
    Excel单元格内自动换行自动行高,打印预览出现内容缺失解决方案
    Winform应用的多语言设置
    单例模式创建窗口
    相似命名的字符串高效拼接
    利用dynamic动态创建对象
    设置全局快捷键
  • 原文地址:https://www.cnblogs.com/bzfsdr/p/13384545.html
Copyright © 2020-2023  润新知