当前位置: 首页 > 图灵资讯 > 技术篇> waiting on <0x7f9c2c4e>(a java.util.concurrent.locks.AbstractQueuedSynchroni

waiting on <0x7f9c2c4e>(a java.util.concurrent.locks.AbstractQueuedSynchroni

来源:图灵教育
时间:2023-08-11 11:08:14

Java并发编程AbstractQuedSynchronizer

Java并发编程,AbstractQueuedSynchronizer(以下简称AQS)是一个重要的基本类别,它提供了实现同步控制的基本框架。本文将详细介绍AQS的概念、用法和代码示例,并展示如何使用AQS实现一个简单的相互排斥锁。

AQS概述

AQS是Java并发包的一类,它提供了实现同步控制的框架。它是Reentrantlock、CountDownLatch、并发工具的基础,如Semaphore。AQS内部使用FIFO队列来管理等待线程,并为子类实现提供了一些方法。AQS的核心思想是使用int状态变量来表示同步状态,通过锁的获取和释放来改变状态,并根据不同的状态来确定线程的阻塞和唤醒。

AQS源码分析

AQS的源代码比较复杂,包含了很多细节,这里我们只关注其中的一部分。以下是AQS的部分源代码:

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements Serializable {    protected AbstractQueuedSynchronizer() { }    static final class Node {        static final Node SHARED = new Node();        static final Node EXCLUSIVE = null;        Node next;        Node prev;        Thread thread;        int waitStatus;        Node() {            thread = Thread.currentThread();        }    }    private transient volatile Node head;    private transient volatile Node tail;    private volatile int state;    protected final int getState() {        return state;    }    protected final void setState(int newState) {        state = newState;    }    // ...}

从上面的代码片段可以看出,AQS定义了一个节点类Node,有一些常量定义和一些成员变量来存储线程信息和等待状态。AQS还定义了两个实例变量headtail,它们分别表示队列的头和尾,用于管理等待线程。最后,AQS还定义了一个state变量表示同步状态。

使用AQS的示例

为了更好地理解AQS的使用方法,我们将通过一个简单的例子来演示如何使用AQS来实现相互排斥锁。以下是示例代码:

public class Mutex {    private static class Sync extends AbstractQueuedSynchronizer {        protected boolean tryAcquire(int ignore) {            return compareAndSetState(0, 1);        }        protected boolean tryRelease(int ignore) {            return compareAndSetState(1, 0);        }        protected boolean isHeldExclusively() {            return getState() == 1;        }    }    private final Sync sync = new Sync();    public void lock() {        sync.acquire(1);    }    public void unlock() {        sync.release(1);    }    public boolean tryLock() {        return sync.tryAcquire(1);    }    public boolean isLocked() {        return sync.isHeldExclusively();    }}

在上面的代码中,我们定义了一个Mutex类,它是一个互斥锁。Mutex类中有一个内部类Sync继承自AbstractQueuedSynchronizer,并实现了几种控制同步状态的必要方法。Mutex类别中的其他方法是正确的Sync类包装,提供了一些简单的调用方法。

现在让我们来看看如何使用它Mutex类:

public class Main {    private static final Mutex mutex = new Mutex();    public static void main(String[] args) {        Runnable task = () -> {            mutex.lock();            try {                // 临界区代码            } finally {                mutex.unlock();            }        };        // 创建多个线程并启动        Thread thread1 = new Thread(task);        Thread thread2 = new Thread(task);        thread1.start();        thread2.start();    }}

在上述代码中,我们创建了一个代码Mutex实例mutex,并在Main类的main该方法使用两个线程来执行临界区代码。通过调用mutex.lock()mutex.unlock(),我们可以确保在同一时刻只能执行一个线程