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在并发中是一个非常重要的基础类,它定义了很多同步组件需要的方法。通过这些方法开发者可以简单的实现一个相关的锁。

    

 ================================================================================== 

不管岁月里经历多少辛酸和艰难,告诉自己风雨本身就是一种内涵,努力的面对,不过就是一场命运的漂流,既然在路上,那么目的地必然也就是前方。


==================================================================================

    

    

  

  

猜你喜欢

转载自www.cnblogs.com/wait-pigblog/p/9315700.html