共计 2837 个字符,预计需要花费 8 分钟才能阅读完成。
前言
又迎来了一年一度的金三银四,尽管说往年的大环境不好,然而招聘还是在炽热进行中。
面试过 Java 工程师的小伙伴都晓得,Java 中的 AQS 是面试高频题,面试官上来就间接了当地问,AQS 晓得是什么吧,来讲讲它是怎么实现的,以及哪些地方用到了它。
那么接下来,让咱们应用 ChatGPT 并联合本人的了解来讲述一下 AQS 的相干内容。
什么是 AQS
当博主发问 ChatGPT 什么是 AQS 时,ChatGPT 给出了如下答复:
大抵意思就是说,AQS 全称 AbstractQueuedSynchronizer,是 Java 中并发包中用于实现锁和其余同步器的根底框架。它应用了 CAS 操作和 unsafe 类来实现同步器的状态更新以及线程的挂起和唤醒等操作,提供了一种通用的、高效且可扩大的同步机制,能够用来构建各种同步组件。
AQS 外部保护了一个 FIFO 队列,用于存储期待获取同步状态的线程。同时定义了一些模板办法,这些办法被子类实现,用于实现不同类型的同步器,例如 ReentrantLock、CountDownLatch、Semaphore 等。
AQS 应用了一种独特的模板办法设计模式,应用外部状态(一个 volatile 润饰的 state 变量)来管制同步器的行为,子类通过实现模板办法来管制同步器的状态变动。AQS 的外部状态能够被子类用于实现独占式、共享式的同步器。
综上,想要了解 AQS,以下几个方面是必要的:
同步器:AQS 是同步器的一个形象基类,通过继承 AQS 能够构建各种同步组件,如锁、信号量等。
状态:AQS 外部保护了一个状态变量,示意同步器的状态。同步器的具体含意由子类来定义。
队列:AQS 外部应用 FIFO 队列来存储期待获取同步状态的线程。当多个线程同时申请同步状态时,AQS 会将其中一个线程设置为独占模式,即该线程成为获取到同步状态的惟一持有者,其余线程则会被退出到期待队列中。
模板办法:AQS 采纳了模板办法设计模式,在 AQS 中定义了一系列形象办法和钩子办法,子类须要实现这些办法来定义本人的同步逻辑。
CAS 和 volatile:AQS 外部应用了 CAS 和 volatile 等原语来保障同步器的正确性和并发性能。
总之,AQS 是 Java 中并发包中实现锁和其余同步器的根底框架,应用模板办法设计模式和 CAS 操作实现了高效、可扩展性高的同步器。了解 AQS 对于了解 Java 中并发编程的原理和实现十分重要。
AQS 如何实现
那接下来问一下 ChatGPT AQS 是如何实现地:
首先,AQS 的外部保护了一个 FIFO 的双向链表,用于存储期待获取锁的线程。当一个线程调用 acquire 办法时,如果以后没有其余线程持有锁,则间接获取锁;否则,将以后线程退出期待队列,并阻塞线程,直到获取到锁的时候再唤醒。
其次,AQS 还提供了一个 ConditionObject 类,用于实现线程的期待 / 告诉机制。每个 ConditionObject 对象外部都保护了一个期待队列,用于存储期待条件满足的线程。当一个线程调用 await 办法时,将以后线程退出期待队列,并阻塞线程,直到条件满足的时候再唤醒;当一个线程调用 signal 办法时,将期待队列的第一个线程唤醒,使其从期待队列中移除,并退出到同步队列中期待获取锁。在应用 ConditionObject 时,须要先获取锁,能力调用 await、signal 办法。
最初,AQS 还提供了一个 getState 和 setState 办法,用于获取和设置以后同步状态。这个同步状态能够用于实现不同的同步语义,如读写锁中的读锁计数器。在实现自定义同步器时,能够应用这些办法来实现特定的同步语义。
须要留神的是,尽管 AQS 提供了弱小的同步器框架,然而自定义同步器须要十分小心,以避免出现死锁、饥饿等问题。在实现自定义同步器时,须要仔细分析利用场景,理清线程之间的依赖关系,以确保同步器的正确性和高效性。
AQS 实现不可重入锁
上述光说实践可能不易于了解,因而让 ChatGPT 生成一个与 AQS 相干的代码示例:
相干代码如下:
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
public class SimpleLock {
private final Sync sync = new Sync();
private static class Sync extends AbstractQueuedSynchronizer {
@Override
protected boolean tryAcquire(int arg) {if (getState() == 0 && compareAndSetState(0, 1)) {setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
@Override
protected boolean tryRelease(int arg) {if (getState() == 0) {throw new IllegalMonitorStateException();
}
setExclusiveOwnerThread(null);
setState(0);
return true;
}
@Override
protected boolean isHeldExclusively() {return getState() == 1;
}
}
public void lock() {sync.acquire(1);
}
public void unlock() {sync.release(1);
}
}
复制代码
在上述示例代码中,咱们首先定义了一个继承自 AbstractQueuedSynchronizer 的外部类 Sync,用于实现不可重入锁。
而后,咱们在 tryAcquire 办法中尝试获取锁,如果以后状态为 0,且可能应用 CAS 操作将状态批改为 1,示意胜利获取到锁,否则获取锁失败。
在 tryRelease 办法中,咱们开释锁,首先查看以后状态是否为 0,如果是 0,示意以后没有线程持有锁,抛出非法监视器状态异样,否则,应用 CAS 操作将状态批改为 0,并将持有锁的线程设置为 null。
在 isHeldExclusively 办法中,咱们判断以后是否有线程持有锁,如果状态为 1,示意有线程持有锁,返回 true,否则返回 false。
而后,咱们定义一个 SimpleLock 类,应用 Sync 外部类实现不可重入锁。在 lock 办法中,咱们调用 acquire 办法来获取锁;在 unlock 办法中,咱们调用 release 办法来开释锁。
设计一个测试用例,发现正如咱们所意料的那样,获取锁与开释锁的性能失常,且当对象有锁之后,不能再获取到该对象了,即不可重入:
上述示例代码只是 AQS 的一个非常简单的利用,更简单的利用能够参考 Java 中 ReentrantLock、CountDownLatch、Semaphore 等同步器的实现。
后记
以上就是 让 ChatGPT 来浅说 AQS 的所有内容了,心愿本篇博文对大家有所帮忙!