AbstractQueuedSynchronizer 是多线程实现同步的基类,采用先进先出线程队列,队列中存有某些线程,这些线程由于某些状态或条件不满足(例如未获得锁)而进入阻塞状态,当条件满足时(例如持有锁的线程释放了锁)先入队列的阻塞线程被唤醒,它再次判断某些状态或条件是否满足而继续执行或再次进入阻塞状态。
AbstractQueuedSynchronizer 支持两种锁机制,共享锁,独占锁。
共享锁:同一时刻允许多个线程获得锁。
独占锁:同一时刻只允许一条线程能获得锁。
成员变量:private volatile int state,表示某种状态条件,由子类定义其意义。
AQS 提供了对state 操作的方法:
1.getState() 返回state的值
2.setState(int state) 设定state的值
3. 原子的设定state的值:
/** *原子的设定state的值,一般在循环中使用。 * expect 期望值 * update 更新值 * * 如果expect =state,则更新state=update 并返回真,否则返回假 */ protected final boolean compareAndSetState(int expect, int update) { return unsafe.compareAndSwapInt(this, stateOffset, expect, update); }
独占模式相关方法:
/** * 模板方法tryAcquire返回真,表示某种状态或条件满足(主要是根据state判断),当前线程可以继续执行, * 模板方法tryAcquire返回假,表示某种状态或条件不满足(主要是根据state判断),线程加入FIFO队列,当前线程阻塞。直至线程被唤醒(release方法被调用并线程处于队列中head之后的第一个节点位置(FIFO)), * 当前线程会再次判断某种状态或条件是否满足,从而执行或是阻塞 */ public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))//addWaiter(Node.EXCLUSIVE)生成等待节点并存入队列 selfInterrupt(); } public final void acquireInterruptibly(int agr){ ......同上,但支持中断 } final boolean acquireQueued(final Node node, int arg) { try { boolean interrupted = false; for (;;) {//无限循环 final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) {//线程被唤醒后,如果该节点是head之后的第一个节点(FIFO),则再次判断再次调用tryAcquire判断某种状态或条件是否满足,如果满足当前线程可以继续执行,否则再次进入阻塞状态直至再次被唤醒。 setHead(node); p.next = null; // help GC return interrupted; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())//调用LockSupport.park(this)阻塞当前线程 interrupted = true; } } catch (RuntimeException ex) { cancelAcquire(node); throw ex; } } /** *运行中的线程,调用tryRelease方法 *模板方法tryRelease返回真,把阻塞队列中某个线程恢复。 *模板方法tryRelease返回假,则退出。 */ public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h);//调用LockSupport.unpark 把阻塞队中head之后第一个阻塞线程恢复 return true; } return false; }tryAcquire 和 tryRelease方法采用模板模式由子类实现。
ReentrantLock 类使用独占模式:
state=0表示独占锁未被占用,其它线程可以争抢独占锁,抢到锁的线程更新state+=1,表明锁被占用
state>0 表示独占锁被某线程占用,某它相要获得独占锁的线程只能进入阻塞状态,直至持有锁的线程完全释放锁(更新state=0)。
ReentrantLock中非公平锁源码分析:
final void lock() { if (compareAndSetState(0, 1))//如果state=0,即锁未被占用,则获得锁,将state改为1 ,使其它线程不能够获得锁而阻塞 setExclusiveOwnerThread(Thread.currentThread());//设置获得独占锁的线程 else//未抢到锁 acquire(1);//内部调用tryAcquire判断是否能够获得锁,能够获得锁,则继续执行,不能获得锁则阻塞 } /** *获取锁的操作方法 * 返回真 ,获得锁 * 返回假,没有获得锁 */ final boolean tryAcquire(int acquires) {// final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) {//锁未占用 if (compareAndSetState(0, acquires)) {//占用锁,改变state值其它线程就不能获得锁了。 setExclusiveOwnerThread(current);//设定获占锁的线程 return true; } } else if (current == getExclusiveOwnerThread()) {//当前线程已经占用了锁, int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } public void unlock() {//释放锁 sync.release(1);//内部调用tryRelease来判断是否能释放锁 } /** * *返回真,锁被释放 *返回假,锁未被释放 */ protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) {//c==0多重锁完释放,否则还是当前线程独占锁,只不过锁定次数-1了。 free = true; setExclusiveOwnerThread(null); } setState(c); return free; }
共享模式的相关方法:
/** * 当前线程加入队列,如果当前线程位于队列head之后的第一个并tryAcquireShared方法返回值>=0则运行,否则阻塞。 * * 模板方法tryAcquireShared返回值=0,表示某种状态或条件满足(主要是根据state判断),当前线程可以继续执行 * 模板方法tryAcquireShared返回值>0,表示某种状态或条件满足(主要是根据state判断),当前线程可以继续执行,并允许更多的线程运行在共享模式下:将队列中位于当前线程之后的线程唤醒,后续线程如果条件或状态满足可以运行,否则再次进入阻塞状态 * * 模板方法tryAcquireShared返回值<0,表示某种状态或条件不满足(主要是根据state判断),当前线程阻塞。直至线程被唤醒(releaseShared方法被调用,并且线程处于队列中head之后的第一个节点位置(FIFO)), * 当前线程会再次判断某种状态或条件是否满足,从而执行或是阻塞 */ private void doAcquireShared(int arg) { final Node node = addWaiter(Node.SHARED);//共享模式、加入队列 try { boolean interrupted = false; for (;;) { final Node p = node.predecessor(); if (p == head) {//位于头部 int r = tryAcquireShared(arg);//某种状态或条件是否满足 if (r >= 0) { setHeadAndPropagate(node, r);//是否唤醒其它线程 p.next = null; // help GC if (interrupted) selfInterrupt(); return; } } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt());//调用LockSupport.park(this)阻塞当前线程 interrupted = true; } } catch (RuntimeException ex) { cancelAcquire(node); throw ex; } } public final void acquireSharedInterruptibly(int agr){ ......同上,但支持中断 } /** *运行中的线程,把阻塞线程唤醒 * *模板方法tryReleaseShared返回真,把阻塞队列中先进入的线程恢复。 *模板方法tryReleaseShared返回假,则退出。 */ public final boolean releaseShared(int arg) { if (tryReleaseShared(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h);//调用LockSupport.unpark 把阻塞队中head之后第一个阻塞线程恢复 return true; } return false; }
tryAcquireShared 和 tryReleaseShared方法由子类实现。
FutureTask 使用共享模式:
state =1 表示任务线程正在运行,调用get方法的线程只能阻塞,只至线程完成(设定state=2)或线程已取消(设定state=4)
state =2 表示任务线程已运行完成,
state =4 表示任务线程已取消,
FutureTask 源码分析:
/** *get方法返回 Callable任务的结果,如果Callable任务未完成,则线程阻塞直至任务运行完成,获取结果返回 * / public V get() throws InterruptedException, ExecutionException { acquireSharedInterruptibly(0); if (getState() == CANCELLED) throw new CancellationException(); if (exception != null) throw new ExecutionException(exception); return result;//返回 } protected int tryAcquireShared(int ignore) { return ((getState() & (RAN | CANCELLED)) != 0 && runner == null)?1:-1; //Callable任务已运行完或取消,则返回1,GET方法可以继续运行 //Callable任务未运行完成,则返回-1,get方法阻塞,直至任务运行完成,阻塞线程被唤醒 } /** * 线程任务执行方法 */ public void run() { if (!compareAndSetState(0, RUNNING)) return; try { runner = Thread.currentThread(); if (getState() == RUNNING) // recheck after setting thread innerSet(callable.call());//调用callable任务,保存返回结果 else releaseShared(0); // cancel } catch (Throwable ex) { innerSetException(ex); } } void innerSet(V v) { for (;;) { int s = getState(); if (s == RAN) return; if (s == CANCELLED) { // aggressively release to set runner to null, // in case we are racing with a cancel request // that will try to interrupt runner releaseShared(0); return; } if (compareAndSetState(s, RAN)) {//任务状态改成已完成 result = v;//任务运行结果赋值 releaseShared(0);//释放阻塞线程 done(); return; } } } protected boolean tryReleaseShared(int ignore) { runner = null; return true;//返回真,唤醒调用GET方法阻塞线程返回任务结果 }
相关推荐
framework based on class AbstractQueuedSynchronizer. This framework provides common mechanics for atomically managing synchronization state, blocking and unblocking threads, and queuing. The paper ...
主要为大家详细介绍了Java并发系列之AbstractQueuedSynchronizer源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
主要为大家详细介绍了Java并发系列之AbstractQueuedSynchronizer源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
AbstractQueuedSynchronizer.java
主要为大家详细介绍了Java并发系列之AbstractQueuedSynchronizer源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
Java锁之AbstractQueuedSynchronizer,队列同步器实现锁或其它相关同步类的基础类
ReentrantLock Lock 加锁过程源码分析图,AQS 源码分析
本篇文章主要介绍了Java同步框架AbstractQueuedSynchronizer详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
主要为大家详细介绍了Java并发系列之AbstractQueuedSynchronizer源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
并以java锁机制实现基类AbstractQueuedSynchronizer的实现为例,从类(核心属性、方法)设计思路,到对关键代码做注释分析,再到以流程图方式直观解释流程;最后介绍了AbstractQueuedSynchronizer的应用,即如何用它...
Chinese_AQS 添加中文注释, 重新按业务部门开发工程师的思维角度组织代码中的方法顺序, 使中国程序员轻松理解 AbstractQueuedSynchronizer;
8.初识Lock与AbstractQueuedSynchronizer(AQS) 9.深入理解AbstractQueuedSynchronizer(AQS) 10.彻底理解ReentrantLock 11.深入理解读写锁ReentrantReadWriteLock 12.详解Condition的await和signal等待通知机制 13....
java锁和同步器框架的核心 AQS: AbstractQueuedSynchronizer,就是通过调用 LockSupport .park()和 LockSupport .unpark()实现线程的阻塞和唤醒 的。 LockSupport 很类似于二元信号量(只有1个许可证可供使用),如果...
Java 并发编程在现代软件开发中占据重要地位,尤其是在多核处理器的时代。JUC(java.util.concurrent)库是 Java ...4. 同步器(Synchronizers):JUC 中的同步器主要通过 AQS(AbstractQueuedSynchronizer)提供支持。
AbstractQueuedSynchronizer(AQS) 简单来说 AQS 会把所有的请求线程构成一个 CLH 队列,当一个线程执行完毕 (lock.unlock())时会激活自己的后继节点,但正在执行的线程并不在队列中, 而那些等待执行的线程全部...
Java 并发编程中的 JUC(java.util.concurrent)库以及其核心组件 AQS(AbstractQueuedSynchronizer)在构建高性能、可伸缩性的多线程应用方面具有重要的地位。 AQS 是 JUC 中的核心组件,它提供了一个框架,让...
AbstractQueuedSynchronizer(AQS)详解.mp4 使用AQS重写自己的锁.mp4 重入锁原理与演示.mp4 读写锁认识与原理.mp4 细读ReentrantReadWriteLock源码.mp4 ReentrantReadWriteLock锁降级详解.mp4 线程安全性问题简单总结...
14.5.AbstractQueuedSynchronizer 190 14.6.AQSinJava.util.concurrentSynchronizerClasses 192 Summary 194 Chapter 15. Atomic Variables and Non-blocking Synchronization 195 15.1.DisadvantagesofLocking 195 ...
第22节AbstractQueuedSynchronizer(AQS)详解00:49:04分钟 | 第23节使用AQS重写自己的锁00:31:04分钟 | 第24节重入锁原理与演示00:12:24分钟 | 第25节读写锁认识与原理00:18:04分钟 | 第26节细读...