AQS实现独占不可重入锁

548 阅读2分钟

队列同步器AbstractQueuedSynchronizer(AQS)是实现各种锁的关键,因此要了解锁的原理或者自己实现锁必须先了解AQS。

API

获取和修改AQS状态的几个方法

  • protected final int getState(): 获取同步状态
  • protected final void setState(int newState):设置同步状态
  • protected final boolean compareAndSetState(int expect, int update):原子的设置同步状态

第三个,原来的状态与expect相等,则修改为update状态,否则返回false

可以被重写的方法

  • protected boolean tryAcquire(int arg): 独占式获取同步状态,在此方法中需要查询当前状态并判断是否符合预期,然后CAS设置同步状态
  • protected boolean tryRelease(int arg): 独占式释放同步状态, 等待获取同步状态的线程有机会拿到同步状态
  • protected int tryAcquireShared(int arg):共享式获取同步状态,返回>=0表示获取成功,否则表示获取失败
  • protected boolean tryReleaseShared(int arg):共享式释放同步状态
  • protected boolean isHeldExclusively():当前同步器是否在独占模式下被线程占用

AQS提供的模板方法

  • public final void acquire(int arg): 独占式获取同步状态,获取成功则返回,否则进入同步队列等待,会调用重写的tryAcquire(int arg)
  • public final void acquireInterruptibly(int arg):独占是获取同步状态,但是能响应中断,被中断抛异常
  • public final boolean tryAcquireNanos(int arg, long nanosTimeout):独占是获取同步状态,能响应中断,且有超时,超时返回false
  • public final void acquireShared(int arg):共享式获取同步状态,没获取到则进入同步队列,同一时刻可以有多个线程获取到同步状态
  • public final void acquireSharedInterruptibly(int arg):可以被中断
  • public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout):带超时,且能被中断
  • public final boolean release(int arg):独占式释放同步状态,释放后会将同步队列第一个节点唤醒
  • public final boolean releaseShared(int arg): 共享式释放同步状态;
  • public final Collection getQueuedThreads(): 获取同步队列里的线程

一些说明:

1.可以把AQS理解为管理状态的一个东西,然后你可以通过重写它的一些方法定义自己的规则 2.共享式:指几个线程可以同时获得同步状态,独占式:指只能单独的线程获得同步状态

AQS实现独占不可重入锁

LockTest内部结构

方法使用全部可以上面API部分找到

编写锁

同步器编写

锁的方法重写

测试

public static void main(String[] args) {
        Lock lock = new NotReentrantLock();
        //线程1
        new Thread(() -> {
            lock.lock();
            try {
                for (int i = 0; i < 30; i++) {
                    System.out.println(Thread.currentThread().getName() + "--" + i);
                    Thread.sleep(2000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }).start();

        new Thread(() -> {
            lock.lock();
            try {
                for (int i = 0; i < 30; i++) {
                    System.out.println(Thread.currentThread().getName() + "--" + i);
                }

            } finally {
                lock.unlock();
            }
        }).start();
    }