【Java高并发】AQS自定义同步器

【Java高并发】AQS原理及其优化

    • 一、AQS概述
    • 二、基于AQS实现自定义同步器
      • 1. 基于AQS实现的不可重入的独占锁
      • 2. 使用自定义锁实现生产—消费模型

一、AQS概述

【Java高并发】AQS自定义同步器_第1张图片

  • AQS队列:线程等待队列,一个FIFO的双向队列,队列元素的类型为Node,Node中的thread变量用来存放进入AQS队列里面的线程,waitStatus记录当前线程等待状态。AQS中维护了一个队列,获取锁失败(非tryLock())的线程都将进入这个队列中排队,等待锁释放后唤醒下一个排队的线程(互斥锁模式下)。
  • 共享资源状态:AQS中维持了一个单一的状态信息state,可以通过getState、setState、compareAndSetState函数修改其值
  • Condition队列:AQS中还有另一个非常重要的内部类ConditionObject,它实现了Condition接口,主要用于实现条件锁。ConditionObject中也维护了一个队列,这个队列主要用于等待条件的成立,当条件成立时,其它线程将signal这个队列中的元素,将其移动到AQS的队列中,等待占有锁的线程释放锁后被唤醒。

eg:Condition典型的运用场景是在BlockingQueue中的实现,当队列为空时,获取元素的线程阻塞在notEmpty条件上,一旦队列中添加了一个元素,将通知notEmpty条件,将其队列中的元素移动到AQS队列中等待被唤醒。

总之,AQS只是一个框架,只定义了一个接口,具体资源的获取、释放都交由自定义同步器实现。不同的自定义同步器争用共享资源的方式也不同,自定义同步器在实现时只需实现共享资源state的获取与释放方式即可。AQS包含了state变量、加锁线程、等待队列等并发中的核心组件。

二、基于AQS实现自定义同步器

1. 基于AQS实现的不可重入的独占锁

NonReentrantLock定义了一个内部类Sync用来实现具体的锁的操作,Sync则继承了AQS。由于我们实现的是独占模式的锁,所以Sync重写了tryAcquire、tryRelease和isHeldExclusively 3个方法。另外,Sync提供了newCondition这个方法用来支持条件变量。

public class NonReentrantLock implements Lock, Serializable {
  private final Sync sync = new Sync();

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

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

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

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

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

  public Condition newCondition() {
    return sync.newCondition();
  }

  private static class Sync extends AbstractQueuedSynchronizer {
    @Override
    protected boolean isHeldExclusively() {
      return getState() == 1;
    }

    @Override
    protected boolean tryAcquire(int arg) {
      assert arg == 1;
      if (compareAndSetState(0, 1)) {
        setExclusiveOwnerThread(Thread.currentThread());
        return true;
      }
      return false;
    }

    @Override
    protected boolean tryRelease(int arg) {
      assert arg == 1;
      if (getState() == 0) {
        throw new IllegalMonitorStateException();
      }
      setExclusiveOwnerThread(null);
      setState(0);
      return true;
    }

    Condition newCondition() {
      return new ConditionObject();
    }
  }

}

2. 使用自定义锁实现生产—消费模型

调用lock.newCondition创建了两个条件变量,用来进行生产者和消费者线程之间的同步

public class TestNonReentrantLock {
  final static NonReentrantLock lock = new NonReentrantLock();
  final static Condition notFull = lock.newCondition();
  final static Condition notEmpty = lock.newCondition();
  final static Queue<String> queue = new LinkedBlockingDeque<String>();
  final static int queueSize = 10;

  public static void main(String[] args) {
    Thread producer = new Thread(new Runnable() {
      @Override
      public void run() {
        lock.lock();
        try {
          //队列满则等待
          while (queue.size() == queueSize) {
            notEmpty.await();
          }
          //添加元素
          queue.add("hello");
          //唤醒消费线程
          notFull.signalAll();
        } catch (InterruptedException e) {
          e.printStackTrace();
        } finally {
          lock.unlock();
        }
      }
    });
    Thread consumer = new Thread(new Runnable() {
      @Override
      public void run() {
        //获取独占锁
        lock.lock();
        try {
          //队列空则等待
          while (0 == queue.size()) {
            notFull.await();
          }
          //消费
          String str = queue.poll();
          System.out.println(str);
          //唤醒生产线程
          notEmpty.signalAll();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    });
    producer.start();
    consumer.start();

  }
}

你可能感兴趣的:(Java基础)