Java并发编程系列-AbstractQueuedSynchronizer (4)

包括两个部分的内容,第一是开始的校验,如果设置的超时时间小于等于0,表示线程等待立即超时,然后立即转移到同步队列尾部,尝试获取锁;第二是如果设置的超时时间大于等于spinForTimeoutThreshold的值,则将当前线程阻塞指定的时间,这个时间会随着循环的次数不断的减小。

另外的两个等待方法awaitUntil(Date deadline)和await(long time, TimeUnit unit)就不再赘述了,原理完全一致,有一个不同的是awaitUninterruptibly()方法:

awaitUninterruptibly()

public class ConditionObject implements Condition, java.io.Serializable { public final void awaitUninterruptibly() { // 1-将当前线程封装成Node节点并添加到等待队列尾部 Node node = addConditionWaiter(); // 2-释放当前线程所占用的lock,在释放的过程中会唤醒同步队列中的下一个节点 int savedState = fullyRelease(node); boolean interrupted = false; // 3-阻塞当前线程,直到被唤醒 while (!isOnSyncQueue(node)) { LockSupport.park(this);// 阻塞当前线程 if (Thread.interrupted()) interrupted = true; } // 4-自旋尝试获取同步锁 if (acquireQueued(node, savedState) || interrupted) selfInterrupt(); } }

其实就是不响应中断的等待方法,从源码中可以看出,虽然不响应中断,但是仍然保存着中断标志。

下面就来看看唤醒的方法:

signal()

public class ConditionObject implements Condition, java.io.Serializable { public final void signal() { // 1-校验当前线程时候独享式持有共享锁,如果不持有则抛出异常 if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter;// 保存等待队列首节点 // 2-如果队列不为空,则执行头节点唤醒操作 if (first != null) doSignal(first); } private void doSignal(Node first) { do { // 3-如果等待队列只有一个节点,则将lastWaiter更新为null if ( (firstWaiter = first.nextWaiter) == null) lastWaiter = null; first.nextWaiter = null; // 4-尝试将线程节点从等待队列转移到同步队列,如果成功则结束循环,如果失败则再次判断firstWaiter首节点是否为null,如果不是null,则再次循环,否则结束循环 } while (!transferForSignal(first) && (first = firstWaiter) != null); } }

方法解析:

第一步:校验当前线程时候独享式持有共享锁,如果不持有则抛出异常

第二步:如果队列不为空,则执行头节点唤醒操作

第三步:如果等待队列只有一个节点(头节点),则将lastWaiter更新为null

第四步:尝试将线程节点从等待队列转移到同步队列,如果成功则结束循环,如果失败则再次判断firstWaiter首节点是否为null,如果不是null,则再次循环,否则结束循环

signalAll()

public class ConditionObject implements Condition, java.io.Serializable { public final void signalAll() { // 1-校验当前线程时候独享式持有共享锁,如果不持有则抛出异常 if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; // 2-如果队列不为空,则执行节点唤醒操作 if (first != null) doSignalAll(first); } private void doSignalAll(Node first) { lastWaiter = firstWaiter = null;// 要唤醒所有线程节点,那么等待队列就是被清空,那么就将这两个指针置为null // 3-针对等待队列中的节点一个一个进行唤醒操作 do { Node next = first.nextWaiter;// 保存二节点 first.nextWaiter = null; transferForSignal(first);// 将首节点转移到同步队列 first = next;// 重置首节点,将二节点作为新的首节点 } while (first != null); } } 2.3 静态内容解析 public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable { private static final Unsafe unsafe = Unsafe.getUnsafe();// 注入Unsafe实例 private static final long stateOffset;// 同步状态偏移量 private static final long headOffset;// 等待队列的头结点偏移量 private static final long tailOffset;// 等待队列的尾节点偏移量 private static final long waitStatusOffset;// 节点等待状态偏移量 private static final long nextOffset;// 节点的下级节点偏移量 static { try { // 获取这五个字段的内存偏移量并保存到各自的字段中 stateOffset = unsafe.objectFieldOffset (AbstractQueuedSynchronizer.class.getDeclaredField("state")); headOffset = unsafe.objectFieldOffset (AbstractQueuedSynchronizer.class.getDeclaredField("head")); tailOffset = unsafe.objectFieldOffset (AbstractQueuedSynchronizer.class.getDeclaredField("tail")); waitStatusOffset = unsafe.objectFieldOffset (Node.class.getDeclaredField("waitStatus")); nextOffset = unsafe.objectFieldOffset (Node.class.getDeclaredField("next")); } catch (Exception ex) { throw new Error(ex); } } }

从这一部分内容可以看出来AQS底层和ConcurrentHashMap一样是使用CAS来实现原子操作的。

这一部分就是引入Unsafe来实现原子以上几个字段的原子更新。知道即可。

2.4 字段解析

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwwysj.html