欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

AQS同步队列器之一:介绍以及简单使用

程序员文章站 2023-10-27 22:24:04
一、简介 JDK1.5之前都是通过synchronized关键字实现并发同步,而JDK1.5以后Doug Lea大师开发了current包下的类,通过JAVA代码实现了synchronized关键的语义。然而在current包下的这些类的实现大部分都不离不开一个基础组件 AQS(AbstractQu ......

一、简介

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

    

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

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


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