解锁Java并发编程的秘密武器!揭秘AQS,让你的代码从此告别‘锁’事烦恼,多线程同步不再是梦!

简介: 【8月更文挑战第25天】AbstractQueuedSynchronizer(AQS)是Java并发包中的核心组件,作为多种同步工具类(如ReentrantLock和CountDownLatch等)的基础。AQS通过维护一个表示同步状态的`state`变量和一个FIFO线程等待队列,提供了一种高效灵活的同步机制。它支持独占式和共享式两种资源访问模式。内部使用CLH锁队列管理等待线程,当线程尝试获取已持有的锁时,会被放入队列并阻塞,直至锁被释放。AQS的巧妙设计极大地丰富了Java并发编程的能力。

在Java的并发编程中,AbstractQueuedSynchronizer(简称AQS)是一个核心组件,它不仅是实现同步器的基础,也是并发包中多种锁(如ReentrantLock、CountDownLatch等)的底层实现。AQS通过其精巧的设计,为开发者提供了一种高效且灵活的同步机制。

AQS的核心概念
AQS是一个抽象类,全称为AbstractQueuedSynchronizer,它定义了一种基于FIFO(先进先出)队列的同步框架。AQS内部维护了一个volatile的state变量,用于表示同步状态。这个状态变量是AQS的核心,通过它来控制对共享资源的访问。当state为0时,表示没有线程持有锁;当state大于0时,表示有线程持有锁。

AQS支持两种资源共享模式:独占式和共享式。独占式模式下,每次只有一个线程能够持有锁,如ReentrantLock;而共享式模式下,允许多个线程同时访问共享资源,如ReentrantReadWriteLock的读锁部分。

AQS的内部结构
AQS内部使用了一个CLH(Craig, Landin, and Hagersten)队列来管理等待获取锁的线程。这个队列是一个双向链表,通过head和tail两个指针来维护队列的头部和尾部。每个节点(Node)代表一个等待获取锁的线程,节点中包含了线程引用、等待状态等信息。

AQS的工作原理
当一个线程尝试获取锁时,首先会检查state的值。如果state为0,表示当前没有线程持有锁,该线程将成功获取锁,并将state设置为1(或其他值,取决于具体实现)。如果state不为0,表示锁已被其他线程持有,当前线程将被放入等待队列中,并进入阻塞状态。

当持有锁的线程释放锁时,它会将state的值设置为0,并唤醒等待队列中的下一个线程。被唤醒的线程会再次尝试获取锁,如果成功,则继续执行;如果失败,则重新进入等待队列。

示例代码
下面是一个使用AQS实现简单互斥锁的示例代码:

java
import java.util.concurrent.locks.AbstractQueuedSynchronizer;

class Mutex {
private final Sync sync = new Sync();

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

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

private static class Sync extends AbstractQueuedSynchronizer {  
    @Override  
    protected boolean tryAcquire(int acquires) {  
        return compareAndSetState(0, 1);  
    }  

    @Override  
    protected boolean tryRelease(int releases) {  
        setState(0);  
        return true;  
    }  

    @Override  
    protected boolean isHeldExclusively() {  
        return getState() == 1;  
    }  
}  

}

// 使用示例
public class Main {
public static void main(String[] args) {
Mutex mutex = new Mutex();

    // 线程1尝试获取锁  
    new Thread(() -> {  
        mutex.lock();  
        try {  
            // 模拟任务执行  
            Thread.sleep(1000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        } finally {  
            mutex.unlock();  
        }  
    }).start();  

    // 线程2尝试获取锁(将在线程1释放锁后获取)  
    new Thread(() -> {  
        mutex.lock();  
        try {  
            // 模拟任务执行  
            Thread.sleep(1000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        } finally {  
            mutex.unlock();  
        }  
    }).start();  
}  

}
在这个示例中,我们定义了一个名为Mutex的互斥锁类,它内部使用了一个继承自AbstractQueuedSynchronizer的Sync类来实现锁的逻辑。通过重写tryAcquire、tryRelease和isHeldExclusively方法,我们实现了简单的锁获取和释放逻辑。

AQS以其简洁而强大的设计,为Java并发编程提供了坚实的基础。通过理解AQS的工作原理,我们可以更加深入地掌握Java并发编程的精髓。

相关文章
|
1天前
|
Java 数据处理 开发者
Java中的Lambda表达式:简化你的代码之路
【8月更文挑战第66天】Lambda表达式在Java 8中首次引入,它为Java开发者提供了一种更简洁、更灵活的编程方式。本文将通过简单易懂的语言和实际代码示例,引导你理解Lambda表达式的基本概念、语法结构以及如何在Java项目中应用它来简化代码。无论你是Java新手还是有经验的开发者,这篇文章都将帮助你更好地掌握这一强大的工具。
29 11
|
8天前
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
22 5
|
6天前
|
Java 开发者
探索Java中的Lambda表达式:简化你的代码之旅##
【8月更文挑战第62天】 Java 8的发布为开发者带来了诸多新特性,其中最引人注目的无疑是Lambda表达式。这一特性不仅让代码变得更加简洁,还极大地提升了开发的效率。本文将通过实际示例,展示如何利用Lambda表达式来优化我们的代码结构,同时探讨其背后的工作原理和性能考量。 ##
|
9天前
|
Java API 开发者
探索Java中的Lambda表达式:简化代码,提升效率
【9月更文挑战第27天】在Java 8中引入的Lambda表达式为编程带来了革命性的变化。通过简洁的语法和强大的功能,它不仅简化了代码编写过程,还显著提升了程序的执行效率。本文将深入探讨Lambda表达式的本质、用法和优势,并结合实例演示其在实际开发中的应用。无论你是Java新手还是资深开发者,都能从中获得启发,优化你的代码设计。
|
2月前
|
Java 数据安全/隐私保护
Java代码的执行顺序和构造方法
构造方法是类的一种特殊方法,用于初始化新对象。在 Java 中,每个类默认都有一个与类名同名的构造方法,无需返回类型。构造方法不能用 static、final、synchronized、abstract 或 native 修饰。它可以重载,通过不同的参数列表实现多种初始化方式。构造方法在对象实例化时自动调用,若未显式声明,默认提供一个无参构造方法。构造代码块和静态代码块分别用于对象和类的初始化,按特定顺序执行。
23 0
|
4月前
|
Java
Java代码的执行顺序
Java代码的执行顺序
23 1
|
Java
Java基础-代码执行顺序(重要)
Java代码初始化顺序:     1.由 static 关键字修饰的(如:类变量(静态变量)、静态代码块)将在类被初始化创建实例对象之前被初始化,而且是按顺序从上到下依次被执行。静态(类变量、静态代码块)属于类本身,不依赖于类的实例。     2.没有 static 关键字修饰的(如:实例变量(非静态变量)、非静态代码块)初始化实际上是会被提取到类的构造器中被执行的,但是会比类构造器中的代码
2347 1
LearnJava(四) | Java代码块执行顺序测试
最近笔试常常遇到考察Java代码块执行顺序的题目,网上查看博客错漏百出,特地自己测试了一下。 如有错漏,希望路过的大佬指出来,以便我进行更改。   先上代码吧! public class ClassA { private static St...
944 0
|
Java 机器学习/深度学习
JAVA代码中加了Try...Catch的执行顺序
public static String getString(){ try { //return "a" + 1/0; return "a"; } catch (Exception e) { System.
下一篇
无影云桌面