关于AQS的学习(一)

本文深入剖析了AQS(AbstractQueuedSynchronizer)的源码,并通过覆写其方法实现了简单的非重入锁。AQS作为Java并发包的核心组件,为自定义同步器提供了基础。文中详细展示了如何利用AQS提供的模板方法来控制锁的获取与释放。
这周看了AQS的源码略有所得,遂写文章记载一下。
AQS的全称是AbstractQueuedSychronizd,这个类是整个java.util.concurrent的核心之一,也可以说这个类是我们学习java 并发的一个突破口。

protected boolean tryAcquire(int arg){};//独占模式的获取
protected boolean tryRelease(int arg){};//独占模式的释放
protected int tryAcquireShared(int arg){};//共享模式的获取
protected int tryRelaseShared(int arg){};//共享模式的释

其中acquire(int arg)会调用tryAcquire(int arg),其它release(int arg)会调用tryRelease(int arg),其它的方法也类似。

如果我们想要实现自己的简单的非重入锁,那么如何去实现呢?首先去覆盖tryAcquire(int arg){}、tryRelease(int arg),就可以实现了简单的非重入锁了。` @Override
protected boolean tryAcquire(int arg) {
// TODO Auto-generated method stub
if (compareAndSetState( 0, 1 )) {
setExclusiveOwnerThread( Thread.currentThread() );
return true;
}
return false;
}

/*
 * (non-Javadoc)
 * 
 * @see
 * java.util.concurrent.locks.AbstractQueuedSynchronizer#tryRelease(int)
 */
@Override
protected boolean tryRelease(int arg) {
    if (getExclusiveOwnerThread().equals( Thread.currentThread() )) {
        setExclusiveOwnerThread( null );
        setState( 0 );
        return true;
    }
    return false;
}

public void lock() {
    acquire( 1 );
}

public boolean tryLock() {
    return tryAcquire( 1 );
}

public void unlock() {
    release( 1 );
}

public boolean isLocked() {
    return isHeldExclusively();
}

`

如上图所示我们就实现了简单的非重入锁,那么为什么这样实现就可以了呢?下一个文章再讲吧
### Java AQS 工作原理及使用详解 #### AQS 的基本概念 AbstractQueuedSynchronizer (简称 AQS),是个用于构建锁和其他同步器的基础框架。它通过个 `int` 类型的状态值 (`state`) 来表示资源的共享情况,并提供了种 FIFO 队列来管理线程之间的竞争。 - **核心字段**: AQS 使用了个名为 `state` 的整数变量来记录同步状态,该变量可以通过原子方式更新以确保线程安全[^2]。 - **队列模型**: 当多个线程争夺同个资源时,未能获得资源的线程会被加入到 CLH(Craig, Landin, and Hagersten locks)队列中等待。这种队列是种双向链表结构,可以有效减少上下文切换带来的开销[^3]。 --- #### 二、AQS 的工作流程 1. **获取锁的过程**: - 调用者尝试获取锁时,如果当前 `state` 值允许,则直接获取并修改 `state`;否则进入同步队列排队。 - 如果线程无法立即获取锁,将会被封装成个节点(Node),并挂载到 CLH 队列中等待唤醒[^4]。 2. **释放锁的过程**: - 当持有锁的线程完成任务后,会调用 `release()` 方法释放锁。 - 此时,AQS 将重新计算 `state` 并通知下个等待中的线程去尝试获取锁。 3. **条件变量支持**: - AQS 提供了对条件变量的支持,这使得开发者可以在某些特定条件下让线程暂停运行直到满足条件后再继续执行。 - 这部分功能主要由 `ConditionObject` 实现,其中涉及两个独立的队列:个是主线程的竞争队列,另个是条件队列[^4]。 --- #### 三、AQS 的两种模式 AQS 支持两种不同的资源共享模式: 1. **独占模式**: - 只能有个线程占用资源,在大多数情况下对应的是互斥锁的行为。 - JDK 中典型的例子有 ReentrantLock 和 Semaphore(permit=1)。 2. **共享模式**: - 多个线程可以同时访问资源,适用于读写锁场景下允许多个只读操作的情况。 - 如 CountDownLatch 或 CyclicBarrier 所使用的机制就是基于此模式实现的。 --- #### 四、AQS 的典型应用案例 以下是几个常见的基于 AQS 构建的工具类及其用途说明: 1. **ReentrantLock** - 是种可重入的互斥锁,提供了与 synchronized 关键字类似的锁定行为,同时还增加了更多高级特性,比如公平锁选项以及中断响应能力等。 2. **CountDownLatch** - 允许个或多个线程直等到其他些线程完成系列操作之后再继续执行。 - 它的核心逻辑在于维护计数值,并随着每次 countDown() 减少直至零触发后续动作。 3. **CyclicBarrier** - 让组线程互相协作到达某个屏障点之前都不能向前推进,非常适合用来解决分阶段处理的任务需求。 4. **Semaphore** - 控制同时刻最多有多少个线程能够访问某项有限资源集合。 5. **ReadWriteLock** - 区分为读锁和写锁两部分,从而提高并发度——即允许多个读者或者单作者存在但不允许两者混合发生冲突。 --- #### 五、代码示例 下面给出段简单的自定义锁实现作为演示如何利用 AQS 创建新的同步组件实例: ```java public class MyMutex extends AbstractQueuedSynchronizer { @Override protected boolean tryAcquire(int acquires) { if (compareAndSetState(0, 1)) { // CAS 操作设置 state setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } @Override protected boolean tryRelease(int releases) { if (getState() == 0) throw new IllegalMonitorStateException(); setExclusiveOwnerThread(null); setState(0); // 清空状态 return true; } public void lock() { acquire(1); } public void unlock() { release(1); } } ``` 上述代码片段展示了怎样借助 AQS 快速搭建起套基础版的手动控制权限分配方案。 --- ### 总结 通过对 AQS学习可以看出其设计精妙之处不仅限于简单地实现了各种类型的锁机构,更重要的是为开发人员提供了个高度灵活且易于扩展的抽象层面上的操作接口集锦。无论是初学者还是资深工程师都能从中受益匪浅!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值