其实juc,即java并发包java.util.concurrent,我们在java开发过程中常常会使用到的,但是我们可能不是那么了解与其息息相关的AQS类,那么你清楚他们有什么作用吗?有兴趣的小伙伴可以跟小编一起来看看哦。
AQS,AbstractQueuedSynchronizer,即队列同步器。它是构建锁或者其他同步组件的基础(例如Semaphore、CountDownLatch、ReentrantLock、ReentrantReadWriteLock),它是juc并发包里面的核心基础组件。
AQS的主要使用方式是继承,子类要通过继承同步器并去实现它的抽象方法来管理同步状态。
AQS使用一个int类型的成员变量state用来表示同步状态(long类型对应的是java.util.concurrent.locks.AbstractQueuedLongSynchronizer),当state>0的时候表示已经获取了锁,当state = 0时则表示释放了锁。它提供了三个方法(getState()、setState(int newState)、compareAndSetState(int expect,int update))来对同步状态state进行操作,当然AQS可以确保对state的操作是安全的。
AQS是通过内置的FIFO同步队列来完成资源获取线程的排队工作的,如果说当前线程获取同步状态失败(锁)了,AQS则会将当前线程以及等待状态等信息构造成一个节点(Node)并且将其加入同步队列,同时会阻塞当前的线程,当同步状态释放的时候,则会把节点中的线程唤醒,使其再次尝试获取同步状态。
juc是JDK5才引入的并发类库,它的基础就是AbstractQueuedSynchronizer抽象类,该类的基础有Lock,CountDownLatch等等,juc在同步器的设计上有获取操作和释放操作。AbstractQueuedSynchronizer(AQS)就是一种同步器的实现。
CountDownLatch类。这个类是一个同步计数器,主要是用于线程间的控制,当CountDownLatch的count计数大于0时,await()会造成阻塞,直到count变为0,await()结束阻塞,使用countDown()会让count减1。CountDownLatch的构造函数可以设置count值,当count=1时,它的作用类似于wait()和notify()的作用。如果说想让其他线程执行完指定程序,其他所有程序都执行结束后再执行,这个时候可以用CountDownLatch,但是由于计数无法被重置,如果需要重置计数,请考虑使用 CyclicBarrier 。
CyclicBarrier类。该类从字面可以理解为循环屏障的意思,它的作用是可以协同多个线程,让多个线程在这个屏障前等到,直到所有的线程都到达了这个屏障的时候,再来一起执行后面的操作。假如说每个线程各有一个await,那么任何一个线程运行到await方法时就会阻塞,直到最后一个线程运行到await时才同时返回。和之前的CountDownLatch相比,它只有await方法,而CountDownLatch是使用countDown()方法将计数器减到0,它创建的参数就是countDown的数量;CyclicBarrier创建时的int参数是await的数量。
Semaphore类。该类用主要是用于控制信号量的个数,构造时传入个数。总数就是控制并发的数量。假如是是5,程序执行前用acquire()方法获得信号,则可用信号变为4,程序执行完通过release()方法归还信号量,可用信号又变为5.如果可用信号为0,acquire就会造成阻塞,等待release释放信号。acquire和release方法可以不在同一个线程中使用。Semaphore实现的功能就类似厕所有5个坑,假如有10个人要上厕所,那么同时只能有多少个人去上厕所呢?同时只能有5个人能够占用,当5个人中 的任何一个人让开后,其中等待的另外5个人中又有一个人可以占用了。另外等待的5个人中可以是随机获得优先机会,也可以是按照先来后到的顺序获得机会,这取决于构造Semaphore对象时传入的参数选项。单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了“锁”,再由另一个线程释放“锁”,这可应用于死锁恢复的一些场合。
Exchanger类。这个类是用来于交换数据的,只能用于两个线程。当一个线程运行到exchange()方法时会阻塞,另一个线程运行到exchange()时,二者交换数据,然后执行后面的程序。
那么以上就是本篇文章的所有内容了,如果觉得对您有所帮助,并且还想了解更多java常见问答的话,记得来关注本站消息哦。