Lock中AbstractQueuedSynchronizer分析

Lock的实现基于队列同步器AbstractQueuedSynchronizer的子类实现的AbstractQueuedSynchronizer用一个int表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。同步器的设计基于模板方法,即开发者需要继承同步器并重写指定的方法,随后同步器组合将在自定义同步组件的过程中,调用同步器的模板方法,这些模板方法又去调用开发者编写的方法。

Lock接口的方法主要为lock(),unlock(),tryLock()(非阻塞式获取锁,没有获取时返回false)等。对于一个需要实现特定需求的Lock(比如独占锁,两个线程共享锁等),都需要通过实现AbstractQueuedSynchronizer的子类来完成。
AbstractQueuedSynchronizer类中需要重写的方法有:tryAcquire(int ),tryRelease(int),tryAcquireShared(int ),tryReleaseShared(int ),isHeldExclusively().其中前面两个是独占式获取锁和释放锁,后面两个是共享式获取和释放锁,最后一个是当前锁是否被同步器独占。
参考《并发编程的艺术》的例子,

	public class Mutex implements Lock{
	
	// 静态内部类,自定义同步器
	private static class Sync extends AbstractQueuedSynchronizer {

		// 当状态为0的是获取锁
		@Override
		protected boolean tryAcquire(int arg) {
		// 如果经过CAS设置状态成功(同步状态设置为1),则代表获取了同步状态
		if (compareAndSetState(0, 1)) {
			setExclusiveOwnerThread(Thread.currentThread());
			return true;
		}
		return false;
		}

		// 释放锁,将状态设置为0
		@Override
		protected boolean tryRelease(int arg) {
		if (getState() == 0)
			throw new IllegalMonitorStateException();

		// 将同步状态重置为0.
		setExclusiveOwnerThread(null);
		setState(0);
		return true;
		}

		// 是否处于独占状态
		@Override
		protected boolean isHeldExclusively() {
		return getState() == 1;
		}

		// 返回一个Condition,每个condition都包含了一个condition队列(暂时不管,后面讲这个Condition是干嘛的.)
		Condition newConditio() {
		return new ConditionObject();
		}

		}

		// 静态内部类继承并重写了AbstractQueuedSynchronizer之后,仅需要将操作代理到Sync上即可
		private final Sync sync = new Sync();

		@Override
		public void lock() {
		sync.acquire(1);
		}

		@Override
		public boolean tryLock() {
		return sync.tryAcquire(1);
		}

		@Override
		public void unlock() {
		sync.release(1);
		}

		@Override
		public Condition newCondition() {
		return sync.newConditio();
		}

		// 不是继承来的,原书中这么写的,官方样例也是这么写的,感觉是对外提供的方法
		public boolean isLocked() {
		return sync.isHeldExclusively();
		}

		// 不是继承来的,原书中这么写的,官方样例也是这么写的,感觉是对外提供的方法
		public boolean hasQueueThreads() {
		return sync.hasQueuedThreads();
		}

		@Override
		public void lockInterruptibly() throws InterruptedException {
		sync.acquireInterruptibly(1);
		}

		@Override
		public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
		return sync.tryAcquireNanos(1, unit.toNanos(time));
		}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}
这是一个自定义的独占式的锁。其实现Lock接口。内部建立一个内部类Sync,Sync继承同步队列,并重写tryAcquire等方法。
		@Override
		protected boolean tryAcquire(int arg) {
		// 如果经过CAS设置状态成功(同步状态设置为1),则代表获取了同步状态
		if (compareAndSetState(0, 1)) {
			setExclusiveOwnerThread(Thread.currentThread());  //如果获取锁,就将当前线程设为独占线程
			return true;
		}
		return false;
		}

在程序中,使用此独占锁的方法是:mutex.lock();
然后,在mutex的lock方法中,调用了同步队列的sync.acquire(1)方法。

   public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

这个方法的逻辑是:
a.首先调用自定义Sync实现的tryAcquire(arg) 方法,尝试获取独占锁。
b. 如果获取不到,(addWaiter(Node.EXCLUSIVE), arg)就将此线程生成同步队列的node元素节点,并尝试加到队列的结尾。
c. acquireQueued(addWaiter(Node.EXCLUSIVE), arg)方法是不断的循环,判断其pre节点是否为头节点,如果是的话,就通过tryAcquire判断是否能独占式获取锁,如果成功的话,将当前节点设为头节点,返回false

    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&  //如果没获取到,就将调用LockSupport的park阻塞此线程
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

acquireQueued方法只有获取锁情况下才会返回,返回后,acquire()方法返回,说明此线程获取锁

在调用Mutex的unlock()方法释放锁时,mutex内部调用Sync的Sync.release(1)方法,同步器中的release方法如下:

   public final boolean release(int arg) {
        if (tryRelease(arg)) {   //调用Sync的tryRelease()方法对锁的释放
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

unparkSuccessor(h)通过LockSupport.unpark(s.thread);唤醒后续节点的线程,其中s=h.next;

2、对于共享式获取锁,其区别和独占式获取锁在于:Lock和Unlock方法中,调用的是tryAcquireShared和tryReleaseShared方法。这两个方法是以原子操作设置状态量,比如能被两个线程占用的锁,状态量就在0,1,2之间不断变动,被一个线程占用,状态量就减1,被线程unlock,状态量就加1。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值