一、什么是AQS
AQS(AbstractQueuedSynchronizer)是多线程同步器,它是JUC(java.util.concurrent)包中多个组件的底层实现,比如像Lock、CountDownLatch、Semaphore等都是用到了AQS。简单理解就是:AQS定义了模板,具体实现由各个子类完成。
二、AQS提供了两种锁机制,分别是排它锁和共享锁
排它锁,就是存在多个线程去竞争同一共享资源的时候,同一个时刻,只允许一个线程去访问该共享资源,也就是说只能有一个线程获取该锁的资源。比如Lock中的ReentrantLock重入锁,它的实现就是用到了AQS的一个排它锁的功能。
共享锁也称为读锁,也就是同一时刻,允许多个线程获取锁的资源,比如CountDownLatch、Semaphore,都用到了AQS中的共享锁的功能。
三、实现原理
它的内部实现的关键就是维护了一个先进先出的队列以及state状态变量。先进先出队列存储的载体叫做Node节点,该节点标识着当前的状态值、是独占还是共享模式以及它的前驱和后继节点等等信息。
详细过程可以描述为:AQS采用了一个int类型的互斥变量state,0表示没有任务线程使用该资源,而大于等于1表示已经有线程正在持有锁资源。一个线程获取锁资源的时候,会判断state是否等于0(无锁状态),如果是,则把这个state更新为1,表示占用到锁,而这个过程中,如果多个线程同时做这样的操作,就会导致线程的安全性问题。因此AQS采用了CAS机制,来保证互斥变量state更新的原子性。未获得到锁的线程通过Unsafe类中的park方法去进行阻塞,把阻塞的线程按照先进先出的原则去放到一个双向链表的结构中,当获得所得线程释放锁之后,会从这个双向链表的头部去唤醒下一个等待的线程再去竞争锁。
四、公平锁和非公平锁
关于锁的的公平性和非公平行,AQS的处理方法是,在竞争锁资源的时候,公平锁要判断双向链表中是否有阻塞的线程,如果有则需要去排队等待。而非公平锁的处理方式是,不管双向链表中是否有阻塞的线程在排队等待,它都会去尝试去修改state变量去竞争锁,这个过程是非公平的。