深入探索:AbstractQueuedSynchronizer 同步器的神秘面纱

简介: 深入探索:AbstractQueuedSynchronizer 同步器的神秘面纱


🌟 一、AQS的底层实现原理

🍊 1. AQS的概述

AQS(AbstractQueuedSynchronizer)是Java提供的一个同步框架,它可以用来实现锁和其他同步工具。AQS的核心思想是共享状态的管理,它通过一个int型的volatile变量来描述同步状态,同时维护一个FIFO队列,用来存放等待线程。在AQS的实现中,同步状态的修改和FIFO队列的维护是通过CAS(Compare-And-Swap)操作实现的。

AQS提供了两种同步方式:独占模式和共享模式。独占模式指的是同一时间只有一个线程可以获取锁,其他线程需要等待独占锁的释放。共享模式指的是多个线程可以同时获取锁,这需要采用读写锁的机制来实现。

🍊 2. AQS的数据结构

在AQS中,同步状态和等待队列是最重要的数据结构。

🎉 (1) 同步状态

同步状态是AQS的核心,它用int类型的变量来描述同步状态。 AQS通过volatile关键字来保证同步状态的可见性,即当同步状态被修改后,所有的线程都可以立即看到最新的值。

同步状态通常用一个整数来表示,整数的值可以表示同步状态的各个属性。在独占模式下,可以使用0表示未锁定状态,1表示锁定状态。在共享模式下,可以使用高16位表示读锁的数量,低16位表示写锁的数量。通过这种方式可以保证同步状态的共享和独占模式可以共存。

🎉 (2) 等待队列

等待队列是AQS中的另一个重要数据结构,用来存储等待获取锁的线程。AQS通过一个FIFO队列来维护等待队列,队列中的每个元素代表一个等待线程。

在AQS的实现中,等待队列使用一个链表来实现。每个节点都包含前驱节点和后继节点,通过这些节点连接起来形成一个FIFO队列。加入队列的方法是通过自旋操作,不断尝试将当前节点加入到队列中。当同步状态的持有者释放锁时,它会尝试唤醒队列中的第一个线程。被唤醒的线程会再次尝试通过CAS操作获取锁,直到它成功获取锁为止。

🍊 3. AQS的锁请求和释放过程

在AQS中,当一个线程需要获取某个同步资源时,它会先尝试通过CAS操作修改同步状态,如果成功获取锁,则直接返回。获取锁的方法取决于同步资源的类型。

🎉 (1) 独占模式

如果是独占资源,那么只有一个线程可以获取锁,其他线程需要等待独占锁释放。此时,获取锁的方法是通过CAS操作修改同步状态,如果成功获取锁,则返回;否则被封装为Node节点,加入到FIFO队列中等待。

如果CAS操作失败,则说明当前线程没有成功获取锁,它就会被封装为一个Node节点,并加入到FIFO队列的尾部。当同步状态的持有者释放锁时,它会尝试唤醒队列中的第一个线程。被唤醒的线程会再次尝试通过CAS操作获取锁,直到它成功获取锁为止。

🎉 (2) 共享模式

如果是共享资源,多个线程可以同时获取锁,这就需要采用读写锁的机制。通过读锁可以实现多个线程同时对同一共享资源进行读操作,而写锁则是独占锁,只允许一个线程进行写操作。获取共享锁的方法是通过尝试通过CAS操作修改同步状态,并判断当前状态是否允许获取共享锁,如果成功获取锁,则返回;否则被封装为Node节点,加入到FIFO队列中等待。

当同步状态的持有者释放锁时,它会尝试唤醒队列中的第一个线程。被唤醒的线程会再次尝试通过CAS操作获取锁,直到它成功获取锁为止。如果获取锁的方式是共享锁,那么会唤醒队列中所有等待线程;如果获取锁的方式是独占锁,那么只会唤醒队列中的第一个线程。

🍊 4. AQS的实战使用场景

AQS是Java提供的一个同步框架,它可以用来实现锁和其他同步工具。AQS的应用非常广泛,常见的应用场景包括:

🎉 (1) ReentrantLock

ReentrantLock是一种可重入锁,它使用AQS来实现锁的功能。在ReentrantLock中,使用一个int变量来表示同步状态。当一个线程获取独占锁时,会将同步状态设置为1,当释放锁时,会将同步状态设置为0。

ReentrantLock支持多种锁模式,包括公平锁和非公平锁。公平锁是指所有等待锁的线程都按照先后顺序依次获取锁,非公平锁是指所有等待锁的线程可以竞争锁。

🎉 (2) Semaphore

Semaphore是一个计数信号量,它也使用AQS来实现。Semaphore的同步状态表示当前还有多少个许可证可用,当一个线程需要获取许可证时,它会尝试通过CAS操作获取许可证,如果成功获取许可证,则计数器减1,否则被封装为Node节点,加入到FIFO队列中等待。

🎉 (3) CountDownLatch

CountDownLatch是一个倒计时门闩,它也使用AQS来实现。CountDownLatch的同步状态表示还有多少个线程需要等待,当一个线程需要等待时,它会将同步状态减1,当同步状态为0时,所有线程都可以继续执行。

🍊 5. AQS的问题和解决方案

AQS在实际应用过程中可能会出现的问题主要有两个:饥饿和死锁。

🎉 (1) 饥饿

饥饿是指某个线程无法获取锁,导致一直处于等待状态,无法执行代码的情况。饥饿的原因有很多,例如锁竞争激烈、锁占用时间过长等。为了解决饥饿问题,可以采用公平锁的方式,保证所有线程都有机会获取锁,避免某个线程一直无法获取锁的情况。

🎉 (2) 死锁

死锁是指两个或多个线程互相持有对方所需的资源,无法继续执行的情况。死锁的原因通常是由于线程获取锁的顺序不当导致的。为了避免死锁,可以规定所有线程获取锁的顺序相同,例如都按照顺序1、2、3的方式获取锁,这样可以避免死锁的发生。

🌟 二、总结

总的来说,AQS是Java中一个非常重要的同步框架,它采用了一种非常高效的实现方式,通过CAS操作和等待队列的维护,实现了同步状态的共享和独占,并支持多种锁模式。AQS的应用非常广泛,可以用来实现ReentrantLock、Semaphore、CountDownLatch等同步工具。在实际使用过程中,需要注意饥饿和死锁问题,采用公平锁和规定获取锁的顺序等方式,可以有效避免这些问题的发生。


相关文章
|
存储 Java
AQS(AbstractQueuedSynchronizer,队列同步器)源码解读
AQS(AbstractQueuedSynchronizer,队列同步器)源码解读
|
前端开发
异步转同步的几种方法
在循环等待中,我们可以使用一个变量来指示异步操作是否已完成。然后,我们可以在循环中检查该变量,如果它指示异步操作已完成,则退出循环。
822 0
|
9月前
|
存储 弹性计算 缓存
阿里云服务器99元和199元与轻量应用服务器38元各自性能、适用场景与选择参考
2025年,阿里云推出了多款低价特惠云服务器,其中轻量应用云服务器2核2G 200M带宽 40G ESSD云盘38元1年,云服务器ECS 2核2G 3M带宽 40G ESSD Entry盘活动价99元1年,而2核4G 5M带宽 80G ESSD Entry盘则仅售199元1年。对于还未使用过阿里云轻量应用服务器和云服务器的用户来说,并不是很清楚他们各自有性能怎么样,主要使用场景有哪些,本文来做个简单介绍与对比,以供参考和选择。
|
6月前
|
存储 JSON Java
你会不会5种牛犇的yml文件读取方式?
我是小假 期待与你的下一次相遇 ~
155 5
|
9月前
|
负载均衡 算法 Nacos
服务注册与发现流程
服务注册与发现流程
|
9月前
|
消息中间件 数据库
如何保证消息的可靠性?可以百分百保证MQ的消息可靠性吗?
如何保证消息的可靠性?可以百分百保证MQ的消息可靠性吗?
|
11月前
|
人工智能 JSON 自然语言处理
Jina Reader:一键将网页内容转为适合 LLM 处理的文本格式,自动抓取和清洗网页内容,支持多种输出格式
Jina Reader 是一款由 Jina AI 推出的开源工具,能够将网页内容快速转换为适合大型语言模型(LLMs)处理的纯文本格式,支持多种输出格式和动态内容处理。
1568 20
Jina Reader:一键将网页内容转为适合 LLM 处理的文本格式,自动抓取和清洗网页内容,支持多种输出格式
|
存储 缓存 前端开发
如何使用 CacheStorage 实现离线缓存
CacheStorage 是一种在客户端存储数据的 API,适用于 Service Worker。通过它,可以实现网页资源的离线缓存,提高应用加载速度和用户体验。使用时,先打开缓存,然后添加、获取或删除资源,确保应用即使在网络不可用时也能正常运行。
|
缓存 网络协议 网络安全
docker中DNS解析问题
【10月更文挑战第6天】
1561 6
|
API Android开发
Android Framework增加API 报错 Missing nullability on parameter
Android Framework增加API 报错 Missing nullability on parameter
712 1

热门文章

最新文章