• JAVAAQS(AbstractQueuedSynchronizer)


    AQS是一个用来构建锁和同步器的框架,使用AQS能简单高效的构造处大量应用广泛的同步器,比如我们提到的ReentrantLock,semaphore,其他的诸如ReentrantReaderWriteLock

    SynchronousQueueFutureTask,都是基于AQS的。当然,我们自己利用AQS也能构造出符合我们需求的同步器。

    提供了原子式的管理同步状态,阻塞和唤醒功能。

    AQS的一个核心思想是,如果被请求的共享资源空闲,则当前请求资源的线程设置为有效的工作线程,并且共享资源设置为锁定状态。

    如果被请求的共享资源被占有,那么就需要一套线程阻塞等待以及被唤醒的锁分配机制,这个机制就是CLH队列锁实现的,即将暂时获取不到的锁线程加入到队列中。

    CLH(Craig,Landin and hagersten)队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在节点之间的关系).AQS是将每条请求共享资源的线程封装成

    一个CLH锁队列的一个节点(Node)来实现锁的分配。

    AQS原理图:

    AQS使用一个int成员变量来表示同步状态,通过内置FIFO队列来获取资源线程的排队工作

    AQS使用CAS对该同步状态进行原子操作并实现值的修改

    public volatile int state;//共享变量、使用volatile修饰保证现场的可见性。

    状态信息通过protected类型的getState(),setState(),compareAndSetState()进行操作。

    通过cas操作原子地 将同步状态值设置同步当前同步状态的值。

    二、AQS对资源的共享方式

    Exclusive(独占):只有一个线程能执行,如ReentrantLock,又可以分为公平锁和非公平锁。

    Share(共享):多个线程可以同时执行,如CountDownLatch、semphore、cyclicBarrier

    公平锁:按照线程在队列中排队顺序,先到先拿。不会抢占

    非公平锁,谁抢到是谁的锁,通过CAS进行抢锁。

    三、AQS底层使用了模板方法模式

    同步器设计是基于末班方法模式的,如果需要自定义同步器一般是这样:

      1、使用者继承AbstractQueuedSynchronizer 并重写指定的方法

      2、将AQS组合在自定义同步组件的实现中,并调用起模板方法,而这些模板方法会调用使用者的重写方法。

    AQS使用了模板方法模式,。自定义同步器时需要重写AQS提供的几个钩子方法:

    protected boolean tryAcquire(int)//独占方式。尝试获取资源,成功则返回true,失败则返回false。
    protected boolean tryRelease(int)//独占方式。尝试释放资源,成功则返回true,失败则返回false。
    protected int tryAcquireShared(int)//共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
    protected boolean tryReleaseShared(int)//共享方式。尝试释放资源,成功则返回true,失败则返回false。
    protected boolean isHeldExclusively()//该线程是否正在独占资源。只有用到condition才需要去实现它。
    

      

    AQS组件总结

    semaphore(信号量)-允许多个线程同时访问:synchronized和reentrantlock都是一次只允许一个线程访问,semaphore(信号量)可以指定多个线程同时访问某个资源

    CountDownLatch(倒计时器):CountDownLatch是一个同步工具类,用来协调多个线程之间的同步。这个工具通常用来控制线程等待,可以让某一个线程等待知道倒计时结束。

    CyclicBarrier(循环栅栏):CyclicBarrier和CountDownLatch非常相似,它可以实现线程间的技术等待,但是它的功能比Countdownlatch更加复杂和强大。

    它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。

    CyclicBarrier 默认的构造方法是 CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用 await() 方法告诉 CyclicBarrier 我已经到达了屏障,然后当前线程被阻塞。

    CountDownLatch什么场景使用?

    CountDownLatch的作用就是允许count个线程阻塞在一个地方,直至所有线程执行完毕。

    项目中有一个多线程读取多个文件处理的场景用到了,读取6个文件,这6个任务都是没有执行顺序依赖的任务,但是我们需要返回给用户将这几个文件的处理结果进行统计整理。

    谓词定义了一个线程池和count为6的CountDownLactch对象。使用线程池处理读取任务,每一个线程处理完后将count-1,调用countDownLatch对象的await方法,直到所有文件读取玩后,

    才执行后续的逻辑。

    ReentrantLock 与 synchronized 区别

  • 相关阅读:
    Leetcode 148. Sort List
    stat/lstat函数使用
    C/C++内存分配和管理
    initializer_list 列表初始化
    extern "C" 含义
    C语言宏定义##连接符和#符的使用
    rabbitMQ日常管理(转)
    java/rabbitmp发布订阅示例(转)
    oracle分页查询
    oracle imp使用
  • 原文地址:https://www.cnblogs.com/Alei777/p/16227965.html
Copyright © 2020-2023  润新知