Java多线程源码分析之:AQS常用应用

Java多线程源码分析之:AQS常用应用

之前我们说到了aqs的基本方法,主要是acquire()获取锁release()释放锁,这是aqs中阻塞队列的方法,还有两个条件队列的基本方法:await()等待signal。当aqs里面还有不少扩展方法,它们其实是为了支持不同的并发工具来定义的。

常见的主要有:

  1. Semaphore:可以理解为操作系统中的信号量,可以看作一种共享锁。
  2. CountDownLatch:可以看作一种计数器,在没到达指定数字时会阻塞所有线程,否则就会同时唤醒所有线程。(计数器是递减,到达0会释放所有线程)
  3. ReentrantLock:经典的互斥锁,它同样是AQS中条件队列的实现类。
  4. CyclicBarrier:它是基于ReentrantLock实现的,和CountDownLatch有些类似,也可以看作一种计数器,唯一的区别是当计数器到达0时会重置到开始的数字。
  5. ReentrantReadWriteLock:读写锁,提供读锁共享写锁阻塞。
  6. ThreadPoolExecutor:大名鼎鼎的线程池(线程池会单独成篇)

锁的白月光:ReentrantLock

ReentrantLock我没记错的话是我接触的第二个Java锁,第一个是使用最简单的synchronized

按照惯例,先来看看ReentrantLock类的总体结构:

image-20220117225537768

我买了可以看到,在ReentrantLock中,有三个内部类,包含了lock和unlock等方法。

其中,FairSync为抽象类,负责对AQS进行了进一步的封装,并实现了一些通用方法。

首先来看看FairSync类(我略去了一些不重要的代码)

    abstract static class Sync extends AbstractQueuedSynchronizer {

        //解锁,由子类实现
        abstract void lock();


        /**
         * 非公平锁的实现
         * 这个方法其实就是AQS中的tryAcquire()方法的实现类
         * Sync的子类会通过此方法来实现AQS中的tryAcquire()方法
         * (AQS中的tryAcquire()方法没有具体实现,默认抛出异常)
         */
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            /**
             * 如果看过我之前的AQS文章看到这里应该会一眼懂,这里就是在
             * 用cas修改state的值,也就是获取锁
             * 这里是第一次加锁的情况
             */
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            /**
             * 这里其实是可重入锁的实现,只有持锁线程才能多次加锁
             */
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                {
                    throw new Error("Maximum lock count exceeded");
                }
                setState(nextc);
                return true;
            }
            return false;
        }

        /**
         * AQS中释放锁的实现类
         * 代码其实不难,就是在更改state的值
         */
        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread()) {
                throw new IllegalMonitorStateException();
            }
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }
    }
posted @ 2022-01-18 18:05  LovelyLM  阅读(130)  评论(0编辑  收藏  举报