AQS同步队列器之一:介绍以及简单使用
一、简介
JDK1.5之前都是通过synchronized关键字实现并发同步,而JDK1.5以后Doug Lea大师开发了current包下的类,通过JAVA代码实现了synchronized关键的语义。然而在current包下的这些类的实现大部分都不离不开一个基础组件----AQS(AbstractQueuedSynchronizer)也就是同步队列器。
AQS定义了一套多线程访问共享资源的同步框架,比如ReentrantLock、CountDownLatch等都是依赖这个基础组件实现的。深入了解AQS有助于对Lock机制实现的原理理解,对并发又更加深入的认知。
二、简单使用示例
在使用AQS基础组件前,先了解一下内部的基本接口。
tryAcquire(int arg):独占式的获取同步状态,实现该方法需要查询当前状态并判断同步状态是否符合预期,然后通过CAS操作更改状态。
tryRelease(int arg):释放同步状态,等待获取同步状态的线程将有机会获取释放的同步状态。
tryAcquireShared(int arg):共享式的获取同步状态,返回大于0代表获取成功,否则就是获取失败。
tryReleaseShared(int arg):共享式的释放同步状态。
isHeldExclusively():判断当前的线程是否已经获取到了同步状态。
在AQS的源码中,这些方法都是没有实现的,都是通过子类自己去实现。这也是AQS的设计核心模版模式的设计方式。通过接口也可以发现,AQS主要提供的就是相关于独占锁的获取释放以及共享锁的获取释放。
通过AQS自定义实现锁的示例
1 class MyLock implements Lock{ 2 3 private static class Sync extends AbstractQueuedSynchronizer{ 4 5 //是否处于占用状态 6 protected boolean isHeldExclusively(){ 7 //当状态为1的时候代表为占用状态 8 return getState() == 1; 9 } 10 //当状态为0时候获取锁 11 public boolean tryAcquire(int acquire){ 12 if(compareAndSetState(0,1)){ 13 setExclusiveOwnerThread(Thread.currentThread());//设置为当前线程拥有 14 return true; 15 } 16 return false; 17 } 18 19 protected boolean tryRelease(int releases){ 20 if(getState() == 0){ 21 throw new IllegalMonitorStateException(); 22 } 23 setExclusiveOwnerThread(null);//当前获取同步状态线程为null 24 setState(0);//将状态设置为0 25 return true; 26 }
实现AQS中定义的模版方法,通过CAS方法获取同步状态,如果内存中的同步状态与预期的状态值相同就用新值替换老值。当获取到了锁就将这个线程赋予这个锁。而tryRelease释放锁就是将当前锁线程赋予null,并将锁同步状态设置为0代表已经释放了这个锁。
上面的方法都是需要子类自己去实现的一些模版方法,而下面的这些方法就是实现自定义同步组件时将会调用的AQS中的实现方法。
acquire(int arg):独占式的获取锁,如果当前线程获取同步状态成功,则由该方法返回,否则将会进入同步队列中等待
acquireInterrupted(int arg):响应中断的获取锁,当前线程未获取同步状态而进入同步队列中,如果当前线程被中断,就会抛出InterruptedException并返回
tryAcquireNanos(int arg,long nanos):在响应获取锁的基础上增加了超时获取锁的功能,如果在超时时间内获取到了锁就返回true,否则就返回false
acquireShared(int arg):共享式的获取同步状态,如果当前线程未获取到同步状态将会进入同步队列等待,在同一时刻可以有多个线程可以获取锁状态
acquireSharedInterrupted(int arg):响应中断的共享获取锁
tryAcquiredSharedNanos(int arg,long nanos):超时获取共享锁
release(int arg):独占式的获取同步状态,该方法会唤醒后继节点
releaseShared(int arg):共享式的释放同步状态
1 private final Sync sync = new Sync(); 2 public void lock(){ 3 sync.acquire(1);//调用AQS中的acquire方法 4 } 5 public boolean tryLocK(){ 6 return sync.tryAcquire(1);//调用AQS中的tryLock方法 7 } 8 public void unlock(){ 9 sync.release();//调用AQS中的释放锁操作 10 }
怎么样评判是否已经获取锁是交由子类自己实现的,而锁获取以后的操作以及锁未被获取的操作都是AQS自己实现的。所以开发者关心的就是怎么样去评判线程是否获取到了锁。
三、总结
AQS在并发中是一个非常重要的基础类,它定义了很多同步组件需要的方法。通过这些方法开发者可以简单的实现一个相关的锁。
==================================================================================
不管岁月里经历多少辛酸和艰难,告诉自己风雨本身就是一种内涵,努力的面对,不过就是一场命运的漂流,既然在路上,那么目的地必然也就是前方。
==================================================================================