AbstractQueuedSynchronizer之AQS

简介: AbstractQueuedSynchronizer之AQS

AbstractQueuedSynchronizer(AQS

概述

AbstractQueuedSynchronizer(简称AQS)是Java中锁和同步器的基础框架,大多数的锁和同步器都是通过继承AQS来实现的。AQS提供了一个灵活的框架,使得开发者可以根据自己的需求来实现各种锁和同步器。本文将介绍AQS的基本原理和实现细节。

基本原理

AQS维护了一个state(状态)属性和一个等待队列。state用来表示同步状态,当state为0时表示锁没有被占用,当state不为0时表示锁已经被占用,state的含义和具体使用方法是由子类定义的。等待队列则用来存储那些请求锁或者同步器的线程。

当一个线程请求锁或同步器时,如果此时state为0,则表示当前线程可以获得锁或同步器,此时会将state设置为1,表示当前锁或同步器已经被占用了。如果此时state不为0,则表示此时锁或同步器正在被其他线程占用,此时当前线程会被加入到等待队列中,等待其他线程释放锁或同步器。

当其他线程释放了锁或同步器时,会唤醒等待队列中的一个线程,使其重新尝试获取锁或同步器。如果此时该线程又成功获取了锁或同步器,则该线程会从等待队列中移除。

实现细节

等待队列

AQS的等待队列是一个双向链表,每个节点表示一个等待线程(或者称为Node),Node继承自AbstractQueuedSynchronizer。下面是Node的定义:

static final class Node {
    // 共享模式
    static final Node SHARED = new Node();
    // 独占模式
    static final Node EXCLUSIVE = null;
    // waitStatus的值表示当前节点需要等待的状态
    static final int CANCELLED =  1;
    static final int SIGNAL    = -1;
    static final int CONDITION = -2;
    static final int PROPAGATE = -3;
    volatile int waitStatus;
    volatile Node prev;
    volatile Node next;
    volatile Thread thread;
    Node nextWaiter;
    final boolean isShared() {
        return nextWaiter == SHARED;
    }
    final Node predecessor() throws NullPointerException {
        Node p = prev;
        if (p == null)
            throw new NullPointerException();
        else
            return p;
    }
    Node() {
    }
    Node(Thread thread, Node mode) {     // Used by addWaiter
        this.nextWaiter = mode;
        this.thread = thread;
    }
    Node(Thread thread, int waitStatus) { // Used by Condition
        this.waitStatus = waitStatus;
        this.thread = thread;
    }
}

Node节点有以下属性:

  • waitStatus:表示节点的状态,可以是以下值:
  • CANCELLED:表示节点已经取消。
  • SIGNAL:表示在释放同步器或者锁时需要唤醒该节点。
  • CONDITION:表示节点在等待Condition时被阻塞。
  • PROPAGATE:表示共享模式下下一个节点需要唤醒。
  • prev:表示当前节点的前一个节点。
  • next:表示当前节点的后一个节点。
  • thread:表示当前节点所对应的线程。
  • nextWaiter:表示下一个等待节点。

等待队列的头节点是一个哑节点,不表示任何一个等待线程。当等待队列不为空时,队首节点表示正在占用同步器或者锁的线程,队列中剩下的节点表示正在等待获取同步器或者锁的线程。

等待队列的操作主要有以下几个:

  • enq(node):将一个节点加入等待队列的尾部。
  • addWaiter(mode):创建一个新的节点并加入到等待队列的尾部。mode表示该节点的模式,可以是独占模式或共享模式。
  • setHead(node):设置等待队列的头节点。
  • unparkSuccessor(node):唤醒等待队列中最近的一个还未被取消的节点。在独占模式下,需要唤醒的节点是当前节点的后继节点;在共享模式下,需要唤醒的节点是等待队列中第一个未被取消的节点。

state属性

AbstractQueuedSynchronizer中,state属性是一个volatile类型的整数,用来表示同步状态。子类可以通过修改state的值来实现自己的同步机制。

state为0时表示同步器或锁没有被占用,当state不为0时表示同步器或锁已经被占用。在独占模式下,state的值为1表示锁已经被占用,在共享模式下,state的值表示正在使用锁的线程数。

state的主要操作有以下几个:

  • getState():获取当前状态的值。
  • setState(newState):设置当前状态的值。
  • compareAndSetState(expect, update):原子性地将当前状态和expect比较,如果相等则将其设置为update,并返回true,否则返回false。

独占模式

AbstractQueuedSynchronizer中的独占模式是最常用的同步机制之一,代表了Java中的锁。

我们来看一下ReentrantLock是如何实现独占模式的。

ReentrantLock

ReentrantLock是一个可重入的互斥锁,它支持公平锁和非公平锁。ReentrantLock继承自AbstractQueuedSynchronizer,在ReentrantLock的构造方法中会调用AbstractQueuedSynchronizer的构造方法来初始化state属性和等待队列。


相关文章
|
安全 Java
【深入理解同步器AQS】
【深入理解同步器AQS】
130 0
|
8月前
|
安全 Java
利用AQS(AbstractQueuedSynchronizer)实现一个线程同步器
利用AQS(AbstractQueuedSynchronizer)实现一个线程同步器
|
8月前
【1】请问什么是 AQS?
【1】请问什么是 AQS?
69 0
|
8月前
|
存储 设计模式 安全
理解 AQS 和 ReentrantLock
在多线程编程中,同步机制是确保线程安全的关键。AQS(AbstractQueuedSynchronizer)和ReentrantLock是Java中两种常见的同步机制,它们各自具有不同的特性和适用场景。了解和掌握这两种机制对于编写高效、安全的并发程序至关重要。这篇文章将带你取了解和掌握这两种机制!另外值得一提的是:公平锁的实现与非公平锁是很像的,只不过在获取锁时不会直接尝试使用CAS来获取锁。只有当队列没节点并且state为0时才会去获取锁,不然都会把当前线程放到队列中。
177 1
|
8月前
|
存储 Java
AbstractQueuedSynchronizer
AbstractQueuedSynchronizer
70 0
|
Java C++
什么是AQS?
AQS(AbstractQueuedSynchronizer)是Java中的一个同步器框架
454 1
|
算法 Java
了解AQS
了解AQS
90 0
|
计算机视觉
AQS
AQS
90 0
|
存储 安全
AQS
一、为什么需要AQS?以及AQS的作用和重要性? AQS(AbstractQueuedSynchronizer)的重要性 AQS被用在ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch、ThreadPoolExcutor的Worker中都有运用(JDK1.8)。AQS是这些类的底层原理,JUC包里很多重要的工具类背后都离不开AQS框架。
138 0
|
设计模式 安全 Java
【AQS】
【AQS】
127 0
【AQS】