当前位置:   article > 正文

java高并发7.1 AQS--CountDownLatch, Semaphore, CyclicBarrier_aqs countdownlatch叫什么

aqs countdownlatch叫什么

文章包含了:

AQS简介

AQS全名:AbstractQueuedSynchronizer,是并发容器J.U.C(java.lang.concurrent)下locks包内的一个类,

J.U.C大大提高了java包的并发性能, 而AQS为J.U.C的核心。

它实现了一个FIFO(FirstIn、FisrtOut先进先出)的队列并并利用一个int类型的变量标识状态。底层实现的数据结构是一个双向链表。

 

Sync queue:同步队列,是一个双向列表。包括head节点和tail节点。head节点主要用作后续的调度。

Condition queue:非必须,单向列表。当程序中存在cindition的时候才会存在此列表。

 

AQS设计思想

  • 使用Node实现FIFO队列,可以用于构建锁或者其他同步装置的基础框架。

  • 利用int类型标识状态。在AQS类中有一个叫做state的成员变量

  • 基于AQS有一个同步组件,叫做ReentrantLock。在这个组件里,stste表示获取锁的线程数,假如state=0,表示还没有线程获取锁,1表示有线程获取了锁。大于1表示重入锁的数量。

  • 继承:子类通过继承并通过实现它的方法管理其状态(acquire和release方法操纵状态)。

  • 可以同时实排它锁共享锁模式(独占、共享),站在一个使用者的角度,AQS的功能主要分为两类:独占和共享。它的所有子类中,要么实现并使用了它的独占功能的api,要么使用了共享锁的功能,而不会同时使用两套api,即便是最有名的子类ReentrantReadWriteLock也是通过两个内部类读锁和写锁分别实现了两套api来实现的。

AQS的大致实现思路

AQS内部维护了一个CLH队列来管理锁。线程会首先尝试获取锁,如果失败就将当前线程及等待状态等信息包装成一个node节点加入到同步队列sync queue里。

接着会不断的循环尝试获取锁,条件是当前节点为head的直接后继才会尝试。如果失败就会阻塞自己直到自己被唤醒。而当持有锁的线程释放锁的时候,会唤醒队列中的后继线程。

____________________________________________________________________________

AQS同步组件*

1.CountDownLatch(闭锁)

 

  • 通过一个计数来保证线程是否需要被阻塞。实现一个或多个线程等待其他线程执行的场景。

我们定义一个CountDownLatch,他是一个同步辅助类, 通过它实现类似于阻塞当前线程的功能通过给定的计数器为其初始化,该计数器是原子性操作,保证同时只有一个线程去操作该计数器。调用该类await方法的线程会一直处于阻塞状态。只有其他线程调用countDown方法(每次使计数器-1),使计数器归零才能继续执行。

核心方法:countDown方法, await方法

执行结果:

我们可以看到finish实在所有线程调用完之后执行的*(await可以保证前面的线程执行完)

如果线程池不再使用了, 记得调用shutdown方法 , 来节省资源 . 

CountDownLatch的await方法还有重载形式,可以设置等待的时间,如果超过此时间,计数器还未清零,则不继续等待:

  1. countDownLatch.await(10, TimeUnit.MILLISECONDS);
  2. //参数1:等待的时间长度
  3. //参数2:等待的时间单位

2.Semaphore

  • 用于保证同一时间并发访问线程的数目。

  • 信号量在操作系统中是很重要的概念,Java并发库里的Semaphore就可以很轻松的完成类似操作系统信号量的控制。Semaphore可以很容易控制系统中某个资源被同时访问的线程个数。

  • 在数据结构中我们学过链表,链表正常是可以保存无限个节点的,而Semaphore可以实现有限大小的列表。

  • 使用场景:仅能提供有限访问的资源。比如数据库连接。

  • Semaphore使用acquire方法和release方法来实现控制:

两个核心方法: acquire方法release方法

应用场景: 

    常用于 仅能提供有限访问的资源, 比如数据库最大的连接数只有20 ,而上层应用的并发数可能远远大于20 ,如果同时操作, 可能会导致异常 , 这个时候就可以用Semaphore来做并发控制. 

举个例子:

 

执行结果:

效果很明显

1.如果想获取多个许可怎么办?

改为一次性获取三个许可

 

运行结果:

相当于同一时间内只能直线一个test的调用, 因为一秒钟只有三个许可, 我们把他全拿了

2.尝试获取许可,获取不到不执行

 

运行结果:

只有三个线程输出了日志

 

原因: 20 个请求会尝试在同一时间执行 , 信号控制量会让背个线程去尝试获取许可 , 但同一时刻只允许3 个线程并发 .

只有三个线程获得了许可 , 其余线程都拿不到许可直接结束了

3.尝试获取许可一段时间,获取不到不执行

*参数1:等待时间长度  参数2:等待时间单位

运行结果:

没有执行完, 只执行了5秒, 每秒执行3个线程

 

3.CyclicBarrier

    也是一个同步辅助类,它允许一组线程相互等待,直到到达某个公共的屏障点(循环屏障)

  • 通过它可以完成多个线程之间相互等待,只有每个线程都准备就绪后才能继续往下执行后面的操作。

  • 每当有一个线程执行了await方法,计数器就会执行+1操作,待计数器达到预定的值,所有的线程再同时继续执行。由于计数器释放之后可以重用(reset方法),所以称之为循环屏障。

  • CountDownLatch区别:

               1、计数器可重复用

               2、描述一个或多个线程等待其他线程的关系/多个线程相互等待

应用场景(与类似CountDownLatch) : 多线程计算数据, 最后合并计算结果

 

 

简单例子:

 

运行结果:

5个线程先准备好 (同步等待, 调用await方法) , 达到屏障数目的时候, 同时运行 

使用方法2:每个线程只等待一段时间

运行结果:

使用方法3:在初始化的时候设置runnable,当线程达到屏障时优先执行runnable

修改的部分, 其他不变

运行结果:

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/148969
推荐阅读
相关标签
  

闽ICP备14008679号