JUC源码阅读之AbstractQueueSynchronizer(一)

AQS(AbstractQueuedSynchronizer)是java.util.concurrent包中的一个基础类,很多并发的工具类都是利用他进行的开发,比如ReetrantLock、Semphore、线程池等等。所以在这里我把AQS的源码进行了整理和阅读,这只是理解整个juc包的一个基础,要想掌握AQS,还需要通过和他的实现类相结合来理解,这篇文章算是本人学习jdk并发源码的第一篇学习笔记,当中理解有错的地方还请大家指正,谢谢。以下的源码都是基于JDK1.8的。
AQS本身是一个抽象类(但是没有抽象方法),他提供了以下几个模板方法供子类实现,从而让子类利用AQS来实现自己的锁机制。这几个方法不设为抽象方法,是为了如果子类只使用独占和共享模式中的一个模式,不需要把所有方法都实现。

		//模板方法,用于独占模式获取锁
		protected boolean tryAcquire(int arg) {
			throw new UnsupportedOperationException();
		}
		
		//模板方法,用于独占模式释放锁
		protected boolean tryRelease(int arg) {
			throw new UnsupportedOperationException();
		}
		
		//共享模式下尝试获取锁。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
		protected int tryAcquireShared(int arg) {
			throw new UnsupportedOperationException();
		}
		
		//共享模式下释放锁,如果释放后允许唤醒后续等待结点返回true,否则false。
		protected boolean tryReleaseShared(int arg) {
			throw new UnsupportedOperationException();
		}
		
		//表示在独占模式下,当前线程是否持有锁
		protected boolean isHeldExclusively() {
			throw new UnsupportedOperationException();
		}

1.类的说明

在jdk中说明摘抄这个类的作用如下

为实现依赖于先进先出 (FIFO) 等待队列的阻塞锁和相关同步器(信号量、事件,等等)提供一个框架。此类的设计目标是成为依靠单个原子 int 值来表示状态的大多数同步器的一个有用基础(private volatile int state)。子类必须定义更改此状态的受保护方法(也就是上面几个模板方法),并定义哪种状态对于此对象意味着被获取或被释放。假定这些条件之后,此类中的其他方法就可以实现所有排队和阻塞机制。子类可以维护其他状态字段,但只是为了获得同步而只追踪使用 getState()setState(int) 和 compareAndSetState(int, int) 方法来操作以原子方式更新的 int 值。

说明中建议,子类应该使用非public的内部类来实现外部类的同步属性,一般源码中都是定义一个内部类Sync来继承。具体的实现我们后面的日记再说。

此类支持独占模式(默认的)和共享模式,在共享模式下成功获取某一锁时,下一个等待线程(如果存在)也必须确定自己是否可以成功获取该锁。ReadWriteLock就实现了两种模式。

AQS定义了一个嵌套类(ConditionObject),子类可以用它来实现Coindition,这个类用于支持独占模式。

2.官方案例,jdk注释中给了两个官方用AQS实现锁的例子

2.1 

这是一个不可重入的独占锁,使用了0来表示无锁的状态,1来表示锁定状态, 非重入锁不需要严格的记录当前锁的拥有者线程,这个类依然做了记录使得易于监控。

 class Mutex implements Lock, java.io.Serializable {

    // Our internal helper class
    private static class Sync extends AbstractQueuedSynchronizer {
      // Report whether in locked state
      protected boolean isHeldExclusively() { 
        return getState() == 1; //如果state状态为1,代表当前当前线程拥有锁
      }

      // Acquire the lock if state is zero在state为0是尝试获取锁,获取锁失败直接返回false
      public boolean tryAcquire(int acquires) {
        assert acquires == 1; // Otherwise unused
       if (compareAndSetState(0, 1)) {//检查是否能够把状态由0改成1
         setExclusiveOwnerThread(Thread.currentThread());//获取锁成功,当前线程设置为拥有锁线程
         return true;
       }
       return false;
      }

      // Release the lock by setting state to zero通过设置state为0来释放锁。
      protected boolean tryRelease(int releases) {
        assert releases == 1; // Otherwise unused
        if (getState() == 0) throw new IllegalMonitorStateException();//state为0,这证明已经被释放
        setExclusiveOwnerThread(null);//将拥有锁线程设置为null
        setState(0);//将state设置为0
        return true;
      }
       
      // Provide a Condition 提供了一个condition,具体操作后面会讲
      Condition newCondition() { return new ConditionObject(); }

      // Deserialize properly
      private void readObject(ObjectInputStream s) 
        throws IOException, ClassNotFoundException {
        s.defaultReadObject();
        setState(0); // reset to unlocked state
      }
    }
    // The sync object does all the hard work. We just forward to it
    private final Sync sync = new Sync();
//通过调用内部类Sync的方法来实现锁。
    public void lock()                { sync.acquire(1); }
    public boolean tryLock()          { return sync.tryAcquire(1); }
    public void unlock()              { sync.release(1); }
    public Condition newCondition()   { return sync.newCondition(); }
    public boolean isLocked()         { return sync.isHeldExclusively(); }
    public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }//查看是否有其他线程正在等待这个锁
    public void lockInterruptibly() throws InterruptedException { //试图获取锁,如果当前线程被中断则终止
      sync.acquireInterruptibly(1);
    }
    public boolean tryLock(long timeout, TimeUnit unit) //试图在指定时间内获取锁
        throws InterruptedException {
      return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
 }
2.2

这是一个类似于CountDownLatch的latch类,除了它值需要单个signal来触发。因为一个latch锁并不是独占锁,它使用shared模式的acquire和release方法。state为1表示释放了锁

 class BooleanLatch {

    private static class Sync extends AbstractQueuedSynchronizer {
		boolean isSignalled() { return getState() != 0; }//状态不为0表示已经锁已经被singalled(释放时把state置为1)
		  
		//重写共享模式的获取锁方法,如果state大于0则返回1,表示获取锁成功,state为0则表示不能获取锁
		protected int tryAcquireShared(int ignore) { 
			return isSignalled()? 1 : -1;//因为只能单个共享,所以只有被Signalled了的状态才能再次获取锁成功 
		} 
		
		protected boolean tryReleaseShared(int ignore) { 
			setState(1);//释放锁,把state设置为1。 
			return true; 
		} 
	} 
	
	private final Sync sync = new Sync(); 
	
	public boolean isSignalled() { return sync.isSignalled(); } 
	public void signal() { sync.releaseShared(1); }//共享模式signal,调用了tryReleaseShared方法,然后释放
	public void await() throws InterruptedException {
		sync.acquireSharedInterruptibly(1);//如果线程被中断就中止,否则调用了tryAcquireShared。如果
											//获取锁失败,则park自己(具体过程看后面的源码解析)
    }
 }


以上就是AQS的一个基本概念,下面一篇就是关于AQS的具体源码分析了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值