当前位置: 首页 > 后端技术 > Java

java开发juc并发AQS介绍

时间:2023-04-01 19:42:48 Java

AQS全称:AbstractQueuedSynchronizer,是java培训学习中JUC并发工具包中ReentrantLock、CountDownLatch、CyclicBarrier等类的底层实现。在本文中,我们主要通过ReentrantLock的使用来大致了解一下AQS的底层代码设计原理,对于源码就不赘述了。只要清楚整体的设计方向,追溯源码并不难。在阅读本文之前,您需要对ReentrantLock的API有一定的了解。ReentrantLock的lock和await方法底层逻辑使用ReentrantLock进行代码块同步,一般有如下写法:1ReentrantLocklock=newReentrantLock(true);2Condition条件=lock.newCondition();34try{5锁.锁();6//.....7条件.await();89}finally{10lock.unlock();11}假设10个线程在T1调用同一个ReentrantLock实例的lock()方法,线程1先获取锁成功,然后线程2调用lock()方法,发现获取锁失败(通过CAS操作标记状态位),则将线程2封装成Node节点放入AQS双向队列,调用LockSupport.park()阻塞挂起。同样的线程3,线程4,...线程10也被阻塞加入队列。至此,t1时刻的AQS队列如图1-1所示:图1-1T4时刻,线程1执行完毕,调用unlock()方法释放锁,取出哨兵节点的下一个节点从AQS队列,此时是线程2,唤醒线程。线程2再次尝试获取锁,如果获取锁成功,就会继续执行线程2的代码。如果失败,则重新打包为Node节点,放入AQS队列。看到这里,你可能会有疑问:为什么线程1的锁释放后唤醒的是线程2,而不是线程3或者线程4?这是因为公平锁和不公平锁。如果使用公平锁,将允许线程按照先进先出的原则抢占锁,非公平锁没有顺序限制。ReentrantLock可以通过构造函数的参数指定,默认使用非公平锁。Lock和Condition结合的原理是什么?通过上面的分析,线程T1成功获取到锁后,在T2调用condition.await()方法会发生以下四种情况:释放锁(标记状态为被CAS操作)阻塞挂起的线程1Thread1封装成一个Node节点,放入条件队列(注意:这里的条件队列和AQS队列不是一回事),用于在其他线程调用condition.signal()或condition.sigalAll()方法,条件队列中的一个或所有Node节点将被移动到AQS队列中。一个锁对应一个AQS队列,多个条件,多个条件队列。条件队列的数量跟在Condition之后。我们用1-2图更直观的理解Lock、Condition、AQS队列、条件队列的关系。作者:小江