AQS使用和原理解析
文章目录AQS如何使用常用APIAbstractQueuedSynchronizer可重写的方法AbstractQueuedSynchronizer已有的方法使用总结AQS的基本原理独占锁VS共享锁公平锁VS非公平锁可重入锁和读写锁AQS如何使用常用APIAbstractQueuedSynchronizer可重写的方法// 独占式获取同步状态,试着获取,成功返回true,反之为fals...
·
文章目录
AQS如何使用
常用API
AbstractQueuedSynchronizer可重写的方法
// 独占式获取同步状态,试着获取,成功返回true,反之为false
protected boolean tryAcquire(int arg)
// 独占式释放同步状态,等待中的其他线程此时将有机会获取到同步状态;
protected boolean tryRelease(int arg)
// 共享式获取同步状态,返回值大于等于0,代表获取成功;反之获取失败;
protected int tryAcquireShared(int arg)
// 共享式释放同步状态,成功为true,失败为false
protected boolean tryReleaseShared(int arg)
// 是否在独占模式下被线程占用。
protected boolean isHeldExclusively()
AbstractQueuedSynchronizer已有的方法
// 获取同步状态值
protected final int getState()
// 设置同步状态值
protected final void setState(int newState)
// 比较同步状态值是否为expect,是则更新为update并返回成功
protected final boolean compareAndSetState(int expect, int update)
// 设置执行线程,父类AbstractOwnableSynchronizer的方法
protected final void setExclusiveOwnerThread(Thread thread)
// 获取可执行权限,不可执行则加入CLH等待
public final void acquire(int arg) {
// tryAcquire通过重写的方法判断是否可执行
if (!tryAcquire(arg) &&
// acquireQueued不可执行则加入队列中等待
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
// 释放锁,并对后续节点进行唤醒
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
使用总结
AbstractQueuedSynchronizer是提供了一个同步的模板,我们需要去继承这个类,我们只需要去重写什么情况下获取和释放同步状态即可,而获取同步状态和释放同步状态的具体实现则由AQS实现。所以重写的那些方法,仅仅是一些简单的对于共享资源state的获取和释放操作。
AQS的基本原理
当线程获取资源失败(比如tryAcquire时试图设置state状态失败),会被构造成一个结点加入CLH队列中,同时当前线程会被阻塞在队列中(通过LockSupport.park实现,其实是等待态)。当持有同步状态的线程释放同步状态时,会唤醒后继结点,然后此结点线程继续加入到对同步状态的争夺中。
ConcurrentHashMap
jdk1.7以后取消了Segment分段锁,采用CAS和synchronized来保证并发安全。数据结构跟HashMap1.8的结构类似,数组+链表/红黑二叉树。
synchronized只锁定当前链表或红黑二叉树的首节点,这样只要hash不冲突,就不会产生并发,效率又提升N倍。
更多推荐
已为社区贡献3条内容
所有评论(0)