017:AQS模板方法模式深度解析:同步器设计的艺术与实战


🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐➕关注👀是作者创作的最大动力🤞

💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝+关注👀欢迎留言讨论

🔥🔥🔥(源码获取 + 调试运行 + 问题答疑)🔥🔥🔥  有兴趣可以联系我

🔥🔥🔥  文末有往期免费源码,直接领取获取(无删减,无套路)

我们常常在当下感到时间慢,觉得未来遥远,但一旦回头看,时间已经悄然流逝。对于未来,尽管如此,也应该保持一种从容的态度,相信未来仍有许多可能性等待着我们。

🔥🔥🔥(免费,无删减,无套路):java swing管理系统源码 程序 代码 图形界面(11套)」
链接:https://pan.quark.cn/s/784a0d377810
提取码:
🔥🔥🔥(免费,无删减,无套路): Python源代码+开发文档说明(23套)」
链接:https://pan.quark.cn/s/1d351abbd11c
提取码:

🔥🔥🔥(免费,无删减,无套路):计算机专业精选源码+论文(26套)」
链接:https://pan.quark.cn/s/8682a41d0097
提取码:
🔥🔥🔥(免费,无删减,无套路):Java web项目源码整合开发ssm(30套)
链接:https://pan.quark.cn/s/1c6e0826cbfd
提取码:

🔥🔥🔥(无删减,无套路):「在线考试系统源码(含搭建教程)」

链接:https://pan.quark.cn/s/96c4f00fdb43
提取码:

引言

在Java并发编程中,AbstractQueuedSynchronizer(AQS)是整个JUC并发包的基石。其精妙之处不仅在于高效的队列管理,更在于它完美运用了模板方法模式,将同步器的通用逻辑与特定策略优雅分离。本文将深入剖析AQS中模板方法模式的设计思想,详细解析模板方法与抽象方法的调用关系,并通过实战案例展示如何基于AQS实现自定义同步器。

模板方法模式在AQS中的体现

设计模式核心思想

模板方法模式定义了一个算法的骨架,将某些步骤延迟到子类中实现。这种模式允许子类在不改变算法结构的情况下重新定义算法的某些步骤。

在AQS中,这种模式体现得淋漓尽致:

  • 固定部分:线程排队、阻塞唤醒、队列管理等通用逻辑

  • 可变部分:资源获取与释放的具体规则,由子类实现

AQS的模板方法分类

AQS提供的模板方法可以分为以下几大类:

1. 独占式获取与释放
 // 模板方法 - 对子类透明
 public final void acquire(int arg)
 public final void acquireInterruptibly(int arg)
 public final boolean tryAcquireNanos(int arg, long nanosTimeout)
 public final boolean release(int arg)
 ​
 // 需要子类实现 - 策略部分
 protected boolean tryAcquire(int arg)
 protected boolean tryRelease(int arg)
2. 共享式获取与释放
 // 模板方法
 public final void acquireShared(int arg)
 public final void acquireSharedInterruptibly(int arg)
 public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
 public final boolean releaseShared(int arg)
 ​
 // 需要子类实现
 protected int tryAcquireShared(int arg)
 protected boolean tryReleaseShared(int arg)
3. 状态查询
 protected boolean isHeldExclusively()

模板方法与抽象方法的调用关系

独占式获取的完整流程

acquire方法为例,让我们看看模板方法如何协调工作:

 public final void acquire(int arg) {
     if (!tryAcquire(arg) &&
         acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
         selfInterrupt();
 }

这个简洁的方法背后隐藏着精妙的协作:

  1. tryAcquire(arg):子类实现的资源获取策略

  2. addWaiter(Node.EXCLUSIVE):AQS提供的节点入队服务

  3. acquireQueued(node, arg):AQS提供的队列管理与阻塞唤醒

  4. selfInterrupt():中断状态恢复

共享式获取的协作机制

共享模式与独占模式的主要区别在于资源获取的语义:

 public final void acquireShared(int arg) {
     if (tryAcquireShared(arg) < 0)
         doAcquireShared(arg);
 }

其中tryAcquireShared的返回值有特殊含义:

  • 正值:获取成功,且后续获取可能成功

  • :获取成功,但后续获取可能失败

  • 负值:获取失败

基于AQS实现自定义同步器

需要重写的方法

根据不同的同步需求,子类需要重写以下方法:

基本配置
 // 必须重写的方法(根据模式选择)
 protected boolean tryAcquire(int arg)      // 独占获取
 protected boolean tryRelease(int arg)      // 独占释放
 protected int tryAcquireShared(int arg)    // 共享获取  
 protected boolean tryReleaseShared(int arg) // 共享释放
 ​
 // 条件支持
 protected boolean isHeldExclusively()      // 是否独占持有

实战案例:实现一个简单的计数锁

让我们通过一个具体的例子来理解如何基于AQS实现自定义同步器:

 public class CountLock extends AbstractQueuedSynchronizer {
     private final int maxCount;
     
     public CountLock(int maxCount) {
         this.maxCount = maxCount;
         setState(0); // 初始化状态
     }
     
     @Override
     protected boolean tryAcquire(int acquires) {
         while (true) {
             int current = getState();
             int next = current + acquires;
             
             // 检查是否超过最大计数
             if (next > maxCount) {
                 return false;
             }
             
             // CAS更新状态
             if (compareAndSetState(current, next)) {
                 return true;
             }
             // CAS失败则重试
         }
     }
     
     @Override
     protected boolean tryRelease(int releases) {
         while (true) {
             int current = getState();
             int next = current - releases;
             
             if (next < 0) {
                 throw new IllegalMonitorStateException();
             }
             
             if (compareAndSetState(current, next)) {
                 return true;
             }
         }
     }
     
     @Override
     protected int tryAcquireShared(int acquires) {
         // 支持共享模式获取
         return tryAcquire(acquires) ? 1 : -1;
     }
     
     @Override
     protected boolean tryReleaseShared(int releases) {
         return tryRelease(releases);
     }
     
     public void lock() {
         acquire(1);
     }
     
     public void unlock() {
         release(1);
     }
 }

实现注意事项

1. 状态管理线程安全

AQS提供了getState()setState()compareAndSetState()方法来安全地管理状态:

 // 正确的状态更新方式
 protected boolean tryAcquire(int arg) {
     int current = getState();
     int next = current + arg;
     if (next < 0) // 溢出检查
         throw new Error("Maximum lock count exceeded");
     return compareAndSetState(current, next);
 }
2. 公平性与非公平性实现

非公平实现

protected boolean tryAcquire(int acquires) {
    // 直接尝试获取,不检查队列
    return compareAndSetState(0, acquires);
}

公平实现

protected boolean tryAcquire(int acquires) {
    if (!hasQueuedPredecessors() && // 检查是否有前驱节点
        compareAndSetState(0, acquires)) {
        return true;
    }
    return false;
}
3. 条件变量的支持

如果需要支持条件变量,必须实现isHeldExclusively()方法:

@Override
protected boolean isHeldExclusively() {
    return getState() > 0; // 根据业务逻辑判断
}

public Condition newCondition() {
    return new ConditionObject();
}

模板方法模式的优势

1. 代码复用

AQS封装了所有复杂的队列管理、线程阻塞和唤醒逻辑,子类只需关注资源管理策略。

2. 框架稳定性

核心算法在AQS中固化,避免了子类实现错误导致整个同步机制崩溃。

3. 扩展灵活性

子类可以自由定义资源管理策略,支持各种复杂的同步场景。

4. 维护便捷性

同步器的通用优化只需要在AQS中完成,所有基于AQS的同步器都能受益。

常见陷阱与最佳实践

1. 避免阻塞在tryXXX方法中

// 错误示例
protected boolean tryAcquire(int arg) {
    while (!available) {
        Thread.sleep(100); // 绝对避免!
    }
    // ...
}

// 正确做法:让AQS处理阻塞
protected boolean tryAcquire(int arg) {
    return available && compareAndSetState(0, 1);
}

2. 正确使用状态值

状态值的设计应该清晰明确:

// 好的设计:状态值有明确含义
public class SimpleLock extends AbstractQueuedSynchronizer {
    protected boolean tryAcquire(int ignore) {
        return compareAndSetState(0, 1); // 0-未锁定,1-已锁定
    }
    
    protected boolean tryRelease(int ignore) {
        setState(0); // 恢复初始状态
        return true;
    }
}

3. 合理处理中断

根据业务需求决定是否支持中断:

// 支持中断
public void lock() throws InterruptedException {
    acquireInterruptibly(1);
}

// 不支持中断  
public void lock() {
    acquire(1);
}

总结

AQS通过模板方法模式完美地分离了同步器的通用逻辑与特定策略,为Java并发编程提供了强大而灵活的基础设施。理解这种设计模式不仅有助于我们更好地使用现有的JUC组件,更能指导我们设计出高质量的自定义同步器。

在实际开发中,基于AQS实现同步器时,关键要明确业务场景的同步语义,合理设计状态管理,并严格遵守线程安全规范。只有这样,才能充分发挥AQS框架的强大能力,构建出高效可靠的并发组件。



往期免费源码对应视频:

免费获取--SpringBoot+Vue宠物商城网站系统

🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐➕关注👀是作者创作的最大动力🤞

💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝+关注👀欢迎留言讨论

🔥🔥🔥(源码 + 调试运行 + 问题答疑)

🔥🔥🔥  有兴趣可以联系我

💖学习知识需费心,
📕整理归纳更费神。
🎉源码免费人人喜,
🔥码农福利等你领!

💖常来我家多看看,
📕网址:扣棣编程
🎉感谢支持常陪伴,
🔥点赞关注别忘记!

💖山高路远坑又深,
📕大军纵横任驰奔,
🎉谁敢横刀立马行?
🔥唯有点赞+关注成!

⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇点击此处获取源码⬇⬇⬇⬇⬇⬇⬇⬇⬇

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值