文章目录
- Java面试必看!AQS的两种同步方式你真的懂了吗?
- 前言:为什么我要写这篇文章?
- 什么是AQS?
- AQS的核心概念
- 独占式同步
- 什么是独占式同步?
- 独占式同步的应用场景
- 独占式同步的核心代码实现
- 独占式同步的关键点
- 共享式同步
- 什么是共享式同步?
- 共享式同步的应用场景
- 共享式同步的核心代码实现
- 共享式同步的关键点
- 独占式同步与共享式同步的区别
- 1. 资源访问方式
- 2. 实现类
- 3. 公平性支持
- 4. 可重入性
- 总结
- 理解这两种机制的区别和应用场景,对于我们编写高效、安全的多线程程序具有重要的意义。
- 📚 领取 | 1000+ 套高质量面试题大合集(无套路,闫工带你飞一把)!
Java面试必看!AQS的两种同步方式你真的懂了吗?
前言:为什么我要写这篇文章?
大家好,我是闫工。今天又要跟大家聊Java了,这次的主题是关于AQS(AbstractQueuedSynchronizer)的两种同步方式。作为一名热爱Java并发编程的老司机,我深知AQS的重要性。每次面试的时候,只要提到AQS,我都能感受到面试官眼中那期待的目光,仿佛在说:“你要是能讲清楚AQS的实现原理,今天这面试应该就稳了!”
但是说实话,AQS真的有点难搞,尤其是它里面的独占式同步和共享式同步这两种机制。很多同学在学习的时候都会被绕进去,觉得这两者之间的区别就是“一个独占资源,另一个可以共享资源”,但具体怎么实现的?怎么区分它们的应用场景?这些问题还是让人摸不着头脑。
所以今天我就来跟大家详细聊聊AQS的两种同步方式。希望这篇文章能让你在面试中对这个问题有一个清晰的认识,也能让你在实际开发中更好地使用这些工具类。
什么是AQS?
首先,我们得先搞清楚AQS到底是什么。AQS是AbstractQueuedSynchronizer的缩写,它是一个用于构建锁和同步器的基础框架。Java中的很多并发工具类都是基于AQS实现的,比如ReentrantLock、Semaphore、CountDownLatch等等。
简单来说,AQS提供了一个队列来管理等待获取资源的线程。当一个线程请求资源而资源不可用时,它会被加入到这个队列中排队等待。当资源被释放后,AQS会通知下一个线程获取资源。
AQS的核心概念
在深入了解AQS的两种同步方式之前,我们需要先了解AQS的一些核心概念:
状态(state):AQS通过一个整型变量来表示资源的状态。这个状态可以是共享模式下的许可数量,也可以是独占模式下的锁持有者信息。
队列(Queue):AQS维护了一个FIFO的等待队列,用来管理那些等待获取资源的线程。
同步器(Sync):AQS通过继承它的子类来实现具体的同步逻辑。这些子类需要重写一些关键方法来定义资源的获取和释放方式。
独占式同步
什么是独占式同步?
独占式同步,顾名思义就是一种“独占”的同步机制。在这种机制下,一次只能有一个线程获取到资源。其他请求资源的线程必须等待,直到当前持有资源的线程释放资源。
独占式同步的应用场景
这种机制最常见的应用场景就是互斥锁,比如ReentrantLock。在多线程环境下,我们常常需要对共享资源进行独占访问,以保证数据的一致性和安全性。
独占式同步的核心代码实现
为了更好地理解独占式同步的实现原理,我们可以参考ReentrantLock的实现方式:
publicclassReentrantLockDemo{privatefinalReentrantLocklock=newReentrantLock();publicvoiddoSomething(){lock.lock();// 尝试获取锁,如果锁被占用则阻塞等待try{// 执行需要加锁的代码}finally{lock.unlock();// 释放锁}}}从上面的代码可以看出,lock.lock()方法用于尝试获取锁。如果锁已经被其他线程持有,当前线程就会进入阻塞状态,直到锁被释放。
独占式同步的关键点
公平性:AQS支持两种类型的锁——公平锁和非公平锁。公平锁保证线程按照排队的顺序获取资源;而非公平锁则允许“插队”,即新来的线程可能会直接尝试获取资源,而不需要等待已经排队的线程。
可重入性:独占式同步通常支持可重入性,也就是说,同一个线程可以多次获取锁而不发生死锁。ReentrantLock就是一个典型的例子。
中断处理:在阻塞状态下,线程是可以被中断的。AQS提供了对中断的友好支持,确保线程在被中断时能够及时释放资源并退出。
共享式同步
什么是共享式同步?
共享式同步与独占式同步相反,允许多个线程同时获取资源。在这种机制下,多个线程可以共享同一个资源,直到达到预定义的最大共享度。
共享式同步的应用场景
这种机制最常见的应用场景是信号量(Semaphore)。例如,在数据库连接池中,我们通常会设置一个最大连接数,允许多个线程共享这些连接,但不能超过这个限制。
共享式同步的核心代码实现
为了更好地理解共享式同步的实现原理,我们可以参考Semaphore的实现方式:
publicclassSemaphoreDemo{privatefinalSemaphoresemaphore=newSemaphore(3);// 最大允许3个线程同时访问publicvoiddoSomething(){try{semaphore.acquire();// 尝试获取许可,如果许可证用完则阻塞等待// 执行需要共享的资源的操作}catch(InterruptedExceptione){Thread.currentThread().interrupt();}finally{semaphore.release();// 释放许可}}}从上面的代码可以看出,semaphore.acquire()方法用于尝试获取许可证。如果许可证已经被用完,当前线程就会进入阻塞状态,直到有许可证被释放。
共享式同步的关键点
公平性:与独占式同步类似,共享式同步也支持公平性和非公平性。公平的信号量保证线程按照排队顺序获取许可;而非公平信号量允许“插队”。
资源控制:共享式同步的核心在于对资源共享度的控制。通过设置一个最大值,可以有效地管理资源的使用情况。
中断处理:同样地,在阻塞状态下,线程是可以被中断的。AQS提供了对中断的友好支持,确保线程在被中断时能够及时释放资源并退出。
独占式同步与共享式同步的区别
通过上面的介绍,我们已经大致了解了独占式同步和共享式同步的基本概念和实现原理。那么,它们之间到底有哪些区别呢?我们可以从以下几个方面来对比:
1. 资源访问方式
- 独占式同步:一次只能有一个线程获取资源。
- 共享式同步:允许多个线程同时获取资源,直到达到预设的最大值。
2. 实现类
- 独占式同步:常见的实现类有ReentrantLock、ReadWriteLock等。
- 共享式同步:常见的实现类有Semaphore、CountDownLatch等。
3. 公平性支持
- 独占式同步:支持公平锁和非公平锁两种类型。
- 共享式同步:支持公平信号量和非公平信号量两种类型。
4. 可重入性
- 独占式同步:通常支持可重入性,如ReentrantLock。
- 共享式同步:一般不支持可重入性。例如,Semaphore不允许同一个线程多次获取许可证而不释放它。
总结
通过本文的介绍,我们可以清晰地看到,独占式同步和共享式同步是两种不同的资源管理机制,适用于不同的应用场景。选择哪种机制取决于具体的业务需求:
- 如果需要对资源共享进行严格的控制,并且允许多个线程同时访问,那么共享式同步(如Semaphore)会是一个更好的选择。
- 如果需要确保只有一个线程能够访问某个资源或代码块,以避免数据不一致和竞态条件,那么独占式同步(如ReentrantLock)会更加合适。
理解这两种机制的区别和应用场景,对于我们编写高效、安全的多线程程序具有重要的意义。
📚 领取 | 1000+ 套高质量面试题大合集(无套路,闫工带你飞一把)!
成体系的面试题,无论你是大佬还是小白,都需要一套JAVA体系的面试题,我已经上岸了!你也想上岸吗?
闫工精心准备了程序准备面试?想系统提升技术实力?闫工精心整理了1000+ 套涵盖前端、后端、算法、数据库、操作系统、网络、设计模式等方向的面试真题 + 详细解析,并附赠高频考点总结、简历模板、面经合集等实用资料!
✅ 覆盖大厂高频题型
✅ 按知识点分类,查漏补缺超方便
✅ 持续更新,助你拿下心仪 Offer!
📥免费领取👉 点击这里获取资料
已帮助数千位开发者成功上岸,下一个就是你!✨