在阅读AQS源码的过程中,也许会存在这样的困惑,为什么当next指针对应的节点为null 或者取消时,从tail 向前遍历寻找最近的一个非取消的节点;

当前任释放时,需要获取继任者;AQS的实现方式是从tail 向前遍历,之所以这样是与入队时的逻辑有关;
见注释

    /*** Inserts node into queue, initializing if necessary. See picture above.* @param node the node to insert* @return node's predecessor*/private Node enq(final Node node) {for (;;) {Node t = tail;if (t == null) { // Must initializeif (compareAndSetHead(new Node()))tail = head;} else {node.prev = t;if (compareAndSetTail(t, node)) {// 假设线程1执行到这里被挂起,此时 next 指针还没有关联到,后新来的线程 n 可能已经被排列到后面去了,所以当 t 被需要时,它的 next 指针还没有设置或者重置;故需要从后到前寻找,而如果找寻下一个,而这个可能被遗漏了;// 故api文档中有这样一说 (Or, said differently, the next-links are an optimization so that we don't usually need a backward scan.)t.next = node;return t;}}}}

源码中有对这个场景的完整描述:

    final boolean isOnSyncQueue(Node node) {if (node.waitStatus == Node.CONDITION || node.prev == null)return false;if (node.next != null) // If has successor, it must be on queuereturn true;/** node.prev can be non-null, but not yet on queue because* 节点的前置前置节点可能为非空,但是尚未在同步队列中,* the CAS to place it on queue can fail. So we have to* 因为cas 入队时可能失败。* traverse from tail to make sure it actually made it.  It* 所以我们不得不后序遍历以确保正确的发现它。* will always be near the tail in calls to this method, and* 它总是在靠近尾节点,当执行这个方法时* unless the CAS failed (which is unlikely), it will be* 除非cas 失败(这不太可能),所以我们不会遍历太多* there, so we hardly ever traverse much.*/return findNodeFromTail(node);}

另一方面如果下一个节点时null(已经被GC ),如何找到下一个有效节点,也只能从后往前找了

AQS 从后往前遍历寻找继任者相关推荐

  1. 记直接插入排序,为什么必须从后往前遍历

    从前往后遍历找到插入位置 @Slf4j public class InsertSort {@Testpublic void test() {int[] arr = new int[]{5, 3, 7, ...

  2. arraylist 后往前遍历_面试官:谈谈常用的Arraylist和Linkedlist的区别

    Arraylist:底层是基于动态数组,根据下表随机访问数组元素的效率高,向数组尾部添加元素的效率高:但是,删除数组中的数据以及向数组中间添加数据效率低,因为需要移动数组. 例如最坏的情况是删除第一个 ...

  3. arraylist 后往前遍历_面试官:请说出线程安全的 ArrayList 有哪些,除了Vector

    以下环境是 JDK 1.8 ArrayList 的初始容量 面试官:你看过 ArrayList 的源码? Python 小星:看过 面试官:那你说下ArrayList 的初始容量是多少? Python ...

  4. arraylist 后往前遍历_ArrayList和LinkedList的深入浅出

    0. 说明 今天无意间看到网上在讨论ArrayList和LinkedList的区别,本文准备从源码中分析下这两个List的底层实现和应用选择. 1. ArrayList 从名称上可以看出来是数组的形式 ...

  5. arraylist 后往前遍历_Java集合框架之ArrayList

    ArrayList介绍 ArrayList是一个数组列表.与Java数组相比,ArrayList相当于一个动态数组.它继承于AbstractList,实现了List, RandomAccess, Cl ...

  6. 转载:二叉树的前中后和层序遍历详细图解(递归和非递归写法)

    二叉树的前中后和层序遍历详细图解(递归和非递归写法) Monster_ii 2018-08-27 17:01:53 50530 收藏 403 分类专栏: 数据结构拾遗 文章标签: 二叉树 前序 中序 ...

  7. 【二叉树前/先序DLR中序LDR后序LRD遍历及镜像翻转,so esay~】

    二叉树前/先序DLR中序LDR后序LRD遍历及镜像翻转 一.名词释义 二叉树的遍历方式,根据遍历根节点的顺序不同,分为三种:前序(先序)遍历(DLR).中序遍历(LDR).后序遍历(LRD). 1.前 ...

  8. 二叉树层次遍历算法 python_二叉树的遍历详解:前、中、后、层次遍历(Python实现)...

    二叉树的遍历详解:前.中.后.层次遍历(Python实现) 二叉树是一种常见的数据结构,而它的常见遍历方法有前序遍历.中序遍历.后续遍历.层次遍历--掌握这几种遍历方法是很有必要的. 假设我们二叉树节 ...

  9. BFS广度优先遍历寻找最短路径(超详细实现过程)

    广度优先遍历寻找最短路径 最近一直想搞A*算法,发现有部分没理解清楚.于是找到了广度优先遍历寻路算法学习了下,想看看可不可以对写A*有什么帮助.广度优先遍历寻路算法本身并不难,概括来说就是像雷达一样, ...

最新文章

  1. 提高网站页面收录的几个方法 返回列表 发新帖回复
  2. JAVAOO 14 16章
  3. MATLAB图像处理-特征提取-形状特征 方法小结
  4. 如何用python进行量化交易_从零开始学习Python和量化交易
  5. Linux中log的目录,/var/log目录中Linux日志文件的功能详解
  6. php larval 胖模型,php – 从缓存中获取的Laravel模型访问器 – 性能增强
  7. POJ 3981.字符串替换
  8. centos7系统根目录扩容
  9. Centos8 搭建linux集群
  10. 进入大厂的面试经验详细总结(P7 拿 offer)
  11. 中国城市统计年鉴1985-2021中国城市年鉴面板数据(完美Excel版)
  12. 基于自适应扰动的疯狂蝴蝶算法-附代码
  13. 经纬度转GeoHash
  14. 相关子查询和不相关子查询
  15. 产品岗常见名词公式及分析方法
  16. APE格式文件全攻略
  17. Oracles数据库学习笔记(三)多表查询
  18. AprilTag: A robust and flflexible visual fifiducial system理解
  19. 盯住Z世代增量,汽车之家818车晚透露哪些营销信号?
  20. 为网页中的图片添加水印的效果

热门文章

  1. 对于云原生时代的后端业务开发和项目系统学习,选Go Or Java?
  2. Java Web开发——自动刷新展示验证码图片
  3. python 获取时间并加8小时
  4. # AES加密原理-详解
  5. C/C++语言 质数统御者(质数的判断)
  6. python创建二维列表
  7. Ruby‘s Adventure
  8. VSCode项目目录结构
  9. js获取当前域名、Url、相对路径和参数以及指定参数——下载文件-window.location.href
  10. 如何将单个pdf合并