Java 中 AQS 的几大经典实现示例详解
作者:Techie峰
AQS是Java并发包中的一个核心基础类,用于构建高效、可扩展的锁和同步器,以下是Java中常见的基于AQS的实现类,每个实现都针对特定场景提供了同步功能,我会逐一介绍它们的主要用途、特点,并提供一个简单的代码示例,感兴趣的朋友一起看看吧
AbstractQueuedSynchronizer(AQS)是Java并发包(java.util.concurrent.locks
)中的一个核心基础类,用于构建高效、可扩展的锁和同步器。它通过一个FIFO队列管理线程的排队和唤醒机制,简化了同步器的开发。以下是Java中常见的基于AQS的实现类,每个实现都针对特定场景提供了同步功能。我会逐一介绍它们的主要用途、特点,并提供一个简单的代码示例。
1.ReentrantLock(可重入锁)
- 用途:实现互斥锁,支持可重入性(同一线程可多次获取锁),避免死锁。常用于替代
synchronized
关键字,提供更灵活的锁控制(如超时、中断)。 - 特点:基于AQS的独占模式(exclusive mode),内部维护一个状态变量记录锁的持有次数。
- 代码示例:
import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockExample { private final ReentrantLock lock = new ReentrantLock(); public void safeMethod() { lock.lock(); // 获取锁 try { // 临界区代码 System.out.println("线程安全操作"); } finally { lock.unlock(); // 释放锁 } } }
2.ReentrantReadWriteLock(可重入读写锁)
- 用途:实现读写分离的锁,允许多个线程同时读共享资源,但写操作时独占锁。适用于读多写少的场景,提升并发性能。
- 特点:基于AQS的共享-独占混合模式,内部使用两个AQS实例(一个用于读锁,一个用于写锁)。
- 代码示例:
import java.util.concurrent.locks.ReentrantReadWriteLock; public class ReadWriteLockExample { private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); private int sharedData = 0; public void readData() { rwLock.readLock().lock(); // 获取读锁 try { System.out.println("读取数据: " + sharedData); } finally { rwLock.readLock().unlock(); // 释放读锁 } } public void writeData(int value) { rwLock.writeLock().lock(); // 获取写锁 try { sharedData = value; System.out.println("写入数据: " + value); } finally { rwLock.writeLock().unlock(); // 释放写锁 } } }
3.Semaphore(信号量)
- 用途:控制对共享资源的并发访问线程数,通过许可证(permits)机制实现限流。常用于资源池(如数据库连接池)。
- 特点:基于AQS的共享模式(shared mode),状态变量表示可用许可证数量。
代码示例:
import java.util.concurrent.Semaphore; public class SemaphoreExample { private final Semaphore semaphore = new Semaphore(3); // 允许最多3个线程同时访问 public void accessResource() throws InterruptedException { semaphore.acquire(); // 获取许可证 try { // 访问共享资源 System.out.println("资源被占用中..."); Thread.sleep(1000); // 模拟操作 } finally { semaphore.release(); // 释放许可证 } } }
4.CountDownLatch(倒计时门闩)
- 用途:让一个或多个线程等待其他线程完成操作后继续执行。常用于初始化任务或批量处理。
- 特点:基于AQS的共享模式,状态变量表示倒计数值(初始化为正数,递减到0时触发)。
代码示例:
import java.util.concurrent.CountDownLatch; public class CountDownLatchExample { public static void main(String[] args) throws InterruptedException { CountDownLatch latch = new CountDownLatch(3); // 初始化计数器为3 for (int i = 0; i < 3; i++) { new Thread(() -> { System.out.println("子线程完成任务"); latch.countDown(); // 计数器减1 }).start(); } latch.await(); // 主线程等待计数器归零 System.out.println("所有任务完成,主线程继续"); } }
5.CyclicBarrier(循环屏障)
- 用途:让一组线程相互等待,直到所有线程都到达某个屏障点后继续执行。支持重用,适用于多阶段任务。
- 特点:虽然CyclicBarrier不是直接继承AQS,但内部使用ReentrantLock(基于AQS)实现同步。
代码示例:
import java.util.concurrent.CyclicBarrier; public class CyclicBarrierExample { public static void main(String[] args) { CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("所有线程到达屏障,执行后续任务")); for (int i = 0; i < 3; i++) { new Thread(() -> { try { System.out.println("线程到达屏障"); barrier.await(); // 等待其他线程 } catch (Exception e) { e.printStackTrace(); } }).start(); } } }
总结
以上是Java中常见的基于AQS的实现类,它们覆盖了互斥锁、读写锁、资源控制、线程协调等多种并发场景。使用这些类时,注意线程安全和资源管理,避免死锁。AQS的设计模式(如状态变量和队列管理)确保了这些实现的高效性和可扩展性。在实际开发中,根据需求选择合适的同步器,并参考官方文档(如java.util.concurrent
包)获取更多细节。
到此这篇关于Java 中 AQS 的几大经典实现的文章就介绍到这了,更多相关java aqs内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!