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的基本原理

CLH
当线程获取资源失败(比如tryAcquire时试图设置state状态失败),会被构造成一个结点加入CLH队列中,同时当前线程会被阻塞在队列中(通过LockSupport.park实现,其实是等待态)。当持有同步状态的线程释放同步状态时,会唤醒后继结点,然后此结点线程继续加入到对同步状态的争夺中。

ConcurrentHashMap

jdk1.7以后取消了Segment分段锁,采用CAS和synchronized来保证并发安全。数据结构跟HashMap1.8的结构类似,数组+链表/红黑二叉树。
synchronized只锁定当前链表或红黑二叉树的首节点,这样只要hash不冲突,就不会产生并发,效率又提升N倍。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐