4.JUC之AQS框架

 

一、简介

1.AQS

AQS是AbstractQueuedSynchronizer的简写,直白的翻译:抽象队列同步器,jdk1.5后出现

 

Provides a framework for implementing blocking locks and related synchronizers (semaphores, events, etc) that rely on first-in-first-out (FIFO) wait queues. This class is designed to be a useful basis for most kinds of synchronizers that rely on a single atomic intvalue to represent state. Subclasses must define the protected methods that change this state, and which define what that state means in terms of this object being acquired orreleased. Given these, the other methods in this class carry out all queuing and blocking mechanics. Subclasses can maintain other state fields, but only the atomically updated int value manipulated using methods getState, setState and compareAndSetState is tracked with respect to synchronization. ——Java docs

翻开源码,首先是一大段的注释,然后可以看开AQS继承自AbstractOwnableSynchronizer。当你翻开AbstractOwnableSynchronizer时,还是先看到小段的说注释。

A synchronizer that may be exclusively owned by a thread. This class provides a basis for creating locks and related synchronizers that may entail a notion of ownership. The AbstractOwnableSynchronizer class itself does not manage or use this information. However, subclasses and tools may use appropriately maintained values to help control and monitor access and provide diagnostics. ——Java docs

 

2.AOS

  生自java1.6,可以由线程以独占的方式拥有的同步器。此类为创建锁和相关同步器(伴随着所有权的概念)提供了基础。

  AbstractOwnableSynchronizer类本身不管理或使用此信息。但是,子类和工具可以使用适当维护的值帮助控制和监视访问以及提供诊断

  简而言之,AOS输出的是一种概念,是一种创建独占锁同步器所有权的概念。他自身并没有规范所有权的管理方式,更没有用到这些信息(所有权的信息)。不过呢,可以帮其子类维护所有者信息。

  可能上面的话仍然不够清晰,下面看看源码。

  AOS提供两个方法一个字段,外带一个空构造方法(可无视)

 1 /**
 2  * The current owner of exclusive mode synchronization.
 3  */
 4 private transient Thread exclusiveOwnerThread; // transient表示该字段不需要序列化,因为AOS实现了Serializable
 5 
 6 protected final void setExclusiveOwnerThread(Thread thread) {
 7     exclusiveOwnerThread = thread;
 8 }
 9 
10 protected final Thread getExclusiveOwnerThread() {
11     return exclusiveOwnerThread;
12 }

  这下明白了吧,就是AOS只维护一个东西------当前谁持有独占式同步器。因此咱们可以当他不存在,继续回到AQS

 

二、作用

  从Java Docs的注释可以知道,AQS是一个框架,一个提供锁或同步器依赖于FIFO等待队列所必要的 “基础设施”的框架,Doug  Lea之所以写个抽象类的目的是为了简化我们实现同步器的工作

也就是说:

  提供一个基于FIFO等待队列,可以用于构建锁或其他同步装置的基础框架。意在能够实现大部分同步需求的基础

  AQS默认提供了独占式和共享式两种模式,JDK对应的实现有ReentrantLock 和 ReentrantReadWriteLock。即除了提供acquire方法之外,还提供了acquireShare。带shared都是共享模式相关操作,默认则是独占模式。

  AQS到底提供了哪些便利呢:

  1.管理状态

  2.实现了线程按安全的CLH队列

  3.实现了同步器公共方法

  4.ConditionObject

 

三、原理

  AQS自身就是一个Wait Queue,CLH lock  queue的变种,CLH队列通常用于自旋锁。

  The wait queue is a variant of a “CLH” (Craig, Landin, and Hagersten) lock queue. CLH locks are normally used for spinlocks. We instead use them for blocking synchronizers, but use the same basic tactic of holding some of the control information about a thread in the predecessor of its node.

  我们知道Queue的底层实现是一个链表结构,我们也知道它可以是单链表,也可以是双链表。AQS实现的是一个双链表结构。即每个节点都存储了前驱和后继两个指针,而且Head节点是dummy节点。入队则tail前驱一个节点,再把新节点接入,然后接入tail节点。

 

  AQS完全通过CAS解决多线程安全问题,即通过Unsafe完成的。具体可以自行阅读AQS源码,在最后几个方法,非常简单

  CAS:compareAndSet,Unsafe的CAS方法的语义是先与期望值进行比较,若不相等返回false;若相等的话,则会把原值修改为新值,再返回true。这个跟 java.util.concurrent.atomic的原子类的CAS方法是一样的

  AQS的实现依赖LockSupport完成阻塞和唤醒,也正是LockSupport的引入使用AQS源码阅读起来逻辑上有点跳跃。

  什么是自旋锁,如下实例实现的即是自旋锁,即是循环等待信息量变成期望值后完成相关操作

 1 // 来自 AQS#doAcquireInterruptibly
 2 private void doAcquireInterruptibly(int arg) throws InterruptedException {
 3     final Node node = addWaiter(Node.EXCLUSIVE);
 4     boolean failed = true;
 5     try {
 6         for (;;) { // 自旋锁
 7             final Node p = node.predecessor();
 8             if (p == head && tryAcquire(arg)) { // 相当于阻塞到信号量变成期望值
 9                 setHead(node);
10                 p.next = null; // help GC
11                 failed = false;
12                 return;
13             }
14             if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
15                 throw new InterruptedException();
16         }
17     } finally {
18         if (failed)
19             cancelAcquire(node);
20     }
21 }

注:CAS算法本身不会自旋,但是可以自旋CAS来不停地发送请求,如java.util.concurrent.atomic包,这个包里面提供了一组原子类

  我们来看一段AtomicBoolean中的自旋锁的代码

public final boolean getAndSet(boolean newValue) {
   for (;;) {
       boolean current = get();
       if (compareAndSet(current, newValue))
           return current;
   }
}



四、用法

  AQS的用法,可以直接参考AQS的注释,另外也可以参考ReentrantLock的写法

  private final Sync sync;

  abstract static class Sync extends AbstractQueuedSynchronizer {

 

  注释指明了,继承AQS需要实现下面五个方法,

  tryAcquire(int arg)

  tryRelease(int arg)

  tryAcquireShared(int arg)

  tryReleaseShared(int arg)

  isHeldExclusively()

  它们带的int参数,用来表示状态,如下面的示例中,用了1和0表示锁和释放

  如你所知,前两个是独占式,中间两个是共享式。最后一个是测试同步器是否正被持有独占锁。即是已有线程持有这个排它锁,且还未释放

  

  后面一篇博客分析这些方法在什么情况下被调用,是怎么和我们的程序联系在一起的

 1 class Mutex implements Lock, java.io.Serializable {
 2 
 3     // Our internal helper class
 4     private static class Sync extends AbstractQueuedSynchronizer {
 5         // Report whether in locked state
 6         protected boolean isHeldExclusively() {
 7             return getState() == 1;
 8         }
 9 
10         // Acquire the lock if state is zero
11         public boolean tryAcquire(int acquires) {
12             assert acquires == 1; // Otherwise unused
13             if (compareAndSetState(0, 1)) {
14                 setExclusiveOwnerThread(Thread.currentThread());
15                 return true;
16             }
17             return false;
18         }
19 
20         // Release the lock by setting state to zero
21         protected boolean tryRelease(int releases) {
22             assert releases == 1; // Otherwise unused
23             if (getState() == 0)
24                 throw new IllegalMonitorStateException();
25             setExclusiveOwnerThread(null);
26             setState(0);
27             return true;
28         }
29 
30         // Provide a Condition
31         Condition newCondition() {
32             return new ConditionObject();
33         }
34 
35         // Deserialize properly
36         private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
37             s.defaultReadObject();
38             setState(0); // reset to unlocked state
39         }
40     }
41 
42     // The sync object does all the hard work. We just forward to it.
43     private final Sync sync = new Sync();
44 
45     public void lock() {
46         sync.acquire(1);
47     }
48 
49     public boolean tryLock() {
50         return sync.tryAcquire(1);
51     }
52 
53     public void unlock() {
54         sync.release(1);
55     }
56 
57     public Condition newCondition() {
58         return sync.newCondition();
59     }
60 
61     public boolean isLocked() {
62         return sync.isHeldExclusively();
63     }
64 
65     public boolean hasQueuedThreads() {
66         return sync.hasQueuedThreads();
67     }
68 
69     public void lockInterruptibly() throws InterruptedException {
70         sync.acquireInterruptibly(1);
71     }
72 
73     public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
74         return sync.tryAcquireNanos(1, unit.toNanos(timeout));
75     }
76 }

 

原文链接:http://blog.youkuaiyun.com/zteny/article/details/54919765

转载于:https://www.cnblogs.com/xuzekun/p/7483978.html

内容概要:本文系统介绍了算术优化算法(AOA)的基本原理、核心思想及Python实现方法,并通过图像分割的实际案例展示了其应用价值。AOA是一种基于种群的元启发式算法,其核心思想来源于四则运算,利用乘除运算进行全局勘探,加减运算进行局部开发,通过数学优化器加速函数(MOA)和数学优化概率(MOP)动态控制搜索过程,在全局探索与局部开发之间实现平衡。文章详细解析了算法的初始化、勘探与开发阶段的更新策略,并提供了完整的Python代码实现,结合Rastrigin函数进行测试验证。进一步地,以Flask框架搭建前后端分离系统,将AOA应用于图像分割任务,展示了其在实际工程中的可行性与高效性。最后,通过收敛速度、寻优精度等指标评估算法性能,并提出自适应参数调整、模型优化和并行计算等改进策略。; 适合人群:具备一定Python编程基础和优化算法基础知识的高校学生、科研人员及工程技术人员,尤其适合从事人工智能、图像处理、智能优化等领域的从业者;; 使用场景及目标:①理解元启发式算法的设计思想与实现机制;②掌握AOA在函数优化、图像分割等实际问题中的建模与求解方法;③学习如何将优化算法集成到Web系统中实现工程化应用;④为算法性能评估与改进提供实践参考; 阅读建议:建议读者结合代码逐行调试,深入理解算法流程中MOA与MOP的作用机制,尝试在不同测试函数上运行算法以观察性能差异,并可进一步扩展图像分割模块,引入更复杂的预处理或后处理技术以提升分割效果。
### Java JUC AQS 并发编程 抽象队列同步器 使用教程 源码解析 #### 什么是AQS? `AbstractQueuedSynchronizer`(简称AQS),作为Java并发包中的核心组件之一,提供了用于实现锁和其他同步器的基础框架。它不仅简化了锁和同步工具的创建过程,还提高了这些工具的工作效率[^2]。 #### 类图结构与工作原理 AQS的设计围绕着一个FIFO(先进先出)等待队列展开,该队列由多个节点组成,每个节点代表了一个正在等待获取资源的线程。每当有新的竞争者未能立即获得所需资源时,就会被构造成一个新的节点并加入到这个队列之中;而当现有持有者释放其持有的资源之后,则会从队头开始依次唤醒后续等待者去尝试占有资源[^5]。 #### 同步模式分类 为了适应不同场景下的需求,AQS支持两种主要类型的同步方式——独占式以及共享式: - **独占式**:一次只允许单个线程访问临界区,在这种情况下其他任何试图进入同一区域内的请求都将被迫挂起直到前序操作完成为止; - **共享式**:允许多个读取者同时存在而不互相干扰,只要不存在写入动作发生即可保持一致性和安全性[^3]。 #### 自定义同步器的关键接口 对于想要利用AQS来构建特定行为逻辑的新类型而言,开发者通常需要重载以下几个抽象方法以适配具体的应用环境: - `tryAcquire(int arg)` 和 `tryRelease(int arg)` - `tryAcquireShared(int arg)` 及 `tryReleaseShared(int arg)` - `isHeldExclusively()` 上述函数分别对应于独占/共享模式下对资源的操作控制流程,通过合理地覆盖它们可以轻松打造出满足业务特性要求的各种高级别同步原语[^1]。 ```java public class CustomSync extends AbstractQueuedSynchronizer { protected boolean tryAcquire(int acquires) { // 实现具体的独占式获取逻辑 return super.tryAcquire(acquires); } protected boolean tryRelease(int releases) { // 实现具体的独占式释放逻辑 return super.tryRelease(releases); } } ``` #### 队列管理机制详解 在实际运行过程中,AQS内部维护了一条双向链表形式的数据结构用来存储各个待处理的任务单元。每当新成员到来之时便会调用`enqueue()`方法将其追加至末端位置上形成完整的链条关系网状链接,并且借助CAS指令保证整个插入过程的安全可靠性质不受外界因素影响破坏[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值