返回顶部
首页 > 资讯 > 精选 >ConcurrentHashMap: 红黑树代理类的示例分析
  • 742
分享到

ConcurrentHashMap: 红黑树代理类的示例分析

2023-06-15 11:06:11 742人浏览 独家记忆
摘要

小编给大家分享一下ConcurrentHashMap: 红黑树代理类的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1、TreeBin内部类分析TreeB

小编给大家分享一下ConcurrentHashMap: 红黑树代理类的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

1、TreeBin内部类分析

TreeBin是红黑树的代理,对红黑树不太了解的,可以参考:

static final class TreeBin<K,V> extends node<K,V> {    // 红黑树根节点    TreeNode<K,V> root;    // 链表的头节点    volatile TreeNode<K,V> first;    // 等待者线程(当前lockState是读状态)    volatile Thread waiter;        volatile int lockState;    // values for lockState(lockstate的值)    static final int WRITER = 1; // set while holding write lock 写锁状态    static final int WAITER = 2; // set when waiting for write lock 等待者状态(写线程在等待)    static final int READER = 4; // increment value for setting read lock 读锁状态        TreeBin(TreeNode<K,V> b) {        // 设置当前节点hash为-2 表示此节点是TreeBin节点        super(TREEBIN, null, null, null);        // 使用first 引用 treeNode链表        this.first = b;        // r 红黑树的根节点引用        TreeNode<K,V> r = null;        // x表示遍历的当前节点        for (TreeNode<K,V> x = b, next; x != null; x = next) {            next = (TreeNode<K,V>)x.next;            // 强制设置当前插入节点的左右子树为null            x.left = x.right = null;            // ----------------------------------------------------------------------            // CASE1:            // 条件成立:说明当前红黑树是一个空树,那么设置插入元素为根节点            // 第一次循环,r一定是null            if (r == null) {                // 根节点的父节点 一定为 null                x.parent = null;                // 颜色改为黑色                x.red = false;                // 让r引用x所指向的对象。                r = x;            }// ----------------------------------------------------------------------            // CASE2:r != null            else {                // 非第一次循环,都会来带else分支,此时红黑树根节点已经有数据了                // k 表示 插入节点的key                K k = x.key;                // h 表示 插入节点的hash                int h = x.hash;                // kc 表示 插入节点key的class类型                Class<?> kc = null;                // p 表示 为查找插入节点的父节点的一个临时节点                TreeNode<K,V> p = r;                // 这里的for循环,就是一个查找并插入的过程                for (;;) {                    // dir (-1, 1)                    // -1 表示插入节点的hash值大于 当前p节点的hash                    // 1 表示插入节点的hash值 小于 当前p节点的hash                    // ph p表示 为查找插入节点的父节点的一个临时节点的hash                    int dir, ph;                    // 临时节点 key                    K pk = p.key;                    // 插入节点的hash值 小于 当前节点                    if ((ph = p.hash) > h)                        // 插入节点可能需要插入到当前节点的左子节点 或者 继续在左子树上查找                        dir = -1;                    // 插入节点的hash值 大于 当前节点                    else if (ph < h)                        // 插入节点可能需要插入到当前节点的右子节点 或者 继续在右子树上查找                        dir = 1;                    // 如果执行到 CASE3,说明当前插入节点的hash 与 当前节点的hash一致,会在case3 做出最终排序。最终                    // 拿到的dir 一定不是0,(-1, 1)                    else if ((kc == null &&                              (kc = comparableClassFor(k)) == null) ||                             (dir = compareComparables(kc, k, pk)) == 0)                        dir = tieBreakOrder(k, pk);                    // xp 想要表示的是 插入节点的 父节点                    TreeNode<K,V> xp = p;                    // 条件成立:说明当前p节点 即为插入节点的父节点                    // 条件不成立:说明p节点 底下还有层次,需要将p指向 p的左子节点 或者 右子节点,表示继续向下搜索。                    if ((p = (dir <= 0) ? p.left : p.right) == null) {                        // 设置插入节点的父节点 为 当前节点                        x.parent = xp;                        // 小于P节点,需要插入到P节点的左子节点                        if (dir <= 0)                            xp.left = x;                            // 大于P节点,需要插入到P节点的右子节点                        else                            xp.right = x;                        // 插入节点后,红黑树性质 可能会被破坏,所以需要调用 平衡方法                        r = balanceInsertion(r, x);                        break;                    }                }            }        }        // 将r 赋值给 TreeBin对象的 root引用。        this.root = r;        assert checkInvariants(root);    }        private final void lockRoot() {        // 条件成立:说明lockState 并不是 0,说明此时有其它读线程在treeBin红黑树中读取数据。        if (!U.compareAndSwapint(this, LOCKSTATE, 0, WRITER))            // 竞争锁的过程            contendedLock(); // offload to separate method    }        private final void unlockRoot() {        // lockstate置为0        lockState = 0;    }        private final void contendedLock() {        boolean waiting = false;        // 表示lock值        int s;        for (;;) {            // ~WAITER = 11111....01            // 条件成立:说明目前TreeBin中没有读线程在访问 红黑树            // 条件不成立:有线程在访问红黑树            if (((s = lockState) & ~WAITER) == 0) {                // 条件成立:说明写线程 抢占锁成功                if (U.compareAndSwapInt(this, LOCKSTATE, s, WRITER)) {                    if (waiting)                        // 设置TreeBin对象waiter 引用为null                        waiter = null;                    return;                }            }            // lock & 0000...10 = 0, 条件成立:说明lock 中 waiter 标志位 为0,此时当前线程可以设置为1了,然后将当前线程挂起。            else if ((s & WAITER) == 0) {                if (U.compareAndSwapInt(this, LOCKSTATE, s, s | WAITER)) {                    waiting = true;                    waiter = Thread.currentThread();                }            }            // 条件成立:说明当前线程在CASE2中已经将 treeBin.waiter 设置为了当前线程,并且将lockState 中表示 等待者标记位的地方 设置为了1            // 这个时候,就让当前线程 挂起。。            else if (waiting)                LockSupport.park(this);        }    }        final TreeNode<K,V> putTreeVal(int h, K k, V v) {        Class<?> kc = null;        boolean searched = false;        for (TreeNode<K,V> p = root;;) {            int dir, ph; K pk;            if (p == null) {                first = root = new TreeNode<K,V>(h, k, v, null, null);                break;            }            else if ((ph = p.hash) > h)                dir = -1;            else if (ph < h)                dir = 1;            else if ((pk = p.key) == k || (pk != null && k.equals(pk)))                return p;            else if ((kc == null &&                      (kc = comparableClassFor(k)) == null) ||                     (dir = compareComparables(kc, k, pk)) == 0) {                if (!searched) {                    TreeNode<K,V> q, ch;                    searched = true;                    if (((ch = p.left) != null &&                         (q = ch.findTreeNode(h, k, kc)) != null) ||                        ((ch = p.right) != null &&                         (q = ch.findTreeNode(h, k, kc)) != null))                        return q;                }                dir = tieBreakOrder(k, pk);            }            TreeNode<K,V> xp = p;            if ((p = (dir <= 0) ? p.left : p.right) == null) {                // 当前循环节点xp 即为 x 节点的爸爸                // x 表示插入节点                // f 老的头结点                TreeNode<K,V> x, f = first;                first = x = new TreeNode<K,V>(h, k, v, f, xp);                // 条件成立:说明链表有数据                if (f != null)                    // 设置老的头结点的前置引用为 当前的头结点。                    f.prev = x;                if (dir <= 0)                    xp.left = x;                else                    xp.right = x;                if (!xp.red)                    x.red = true;                else {                    // 表示 当前新插入节点后,新插入节点 与 父节点 形成 “红红相连”                    lockRoot();                    try {                        // 平衡红黑树,使其再次符合规范。                        root = balanceInsertion(root, x);                    } finally {                        unlockRoot();                    }                }                break;            }        }        assert checkInvariants(root);        return null;    }}

2、treeifyBin方法分析

treeifyBin:TreeBin的成员方法,转换链表为红黑树的方法:

private final void treeifyBin(Node<K,V>[] tab, int index) {    // b:    // n: tab的长度    // sc: sizeCtl    Node<K,V> b; int n, sc;    if (tab != null) {        // ---------------------------------------------------------------------------        // CASE1:        // 条件成立:说明当前table数组长度未达到 64,此时不进行树化操作,而进行扩容操作。        if ((n = tab.length) < MIN_TREEIFY_CAPACITY)            // table进行扩容            tryPresize(n << 1);        // ---------------------------------------------------------------------------        // CASE2:        // 条件成立:说明当前桶位有数据,且是普通node数据。        else if ((b = tabAt(tab, index)) != null && b.hash >= 0) {// 给头元素b加锁            synchronized (b) {                // 条件成立:表示加锁没问题,b没有被其他线程修改过                if (tabAt(tab, index) == b) {                    // 下面的for循环逻辑,目的就是把桶位中的单链表转换成双向链表,便于树化~// hd指向双向列表的头部,tl指向双向链表的尾部                    TreeNode<K,V> hd = null, tl = null;                    for (Node<K,V> e = b; e != null; e = e.next) {                        TreeNode<K,V> p =                            new TreeNode<K,V>(e.hash, e.key, e.val,                                              null, null);                        if ((p.prev = tl) == null)                            hd = p;                        else                            tl.next = p;                        tl = p;                    }// 把node单链表转换的双向链表转换成TreeBin对象                    setTabAt(tab, index, new TreeBin<K,V>(hd));                }            }        }    }}

3、find方法分析

find:TreeBin中的查找方法。

final Node<K,V> find(int h, Object k) {    if (k != null) {        // e 表示循环迭代的当前节点:迭代的是first引用的链表        for (Node<K,V> e = first; e != null; ) {            // s 保存的是lock临时状态            // ek 链表当前节点 的key            int s; K ek;            // ----------------------------------------------------------------------            // CASE1:            // (WAITER|WRITER) => 0010 | 0001 => 0011            // lockState & 0011 != 0 条件成立:说明当前TreeBin有等待者线程 或者 目前有写操作线程正在加锁            if (((s = lockState) & (WAITER|WRITER)) != 0) {                if (e.hash == h &&                    ((ek = e.key) == k || (ek != null && k.equals(ek))))                    return e;                e = e.next;            }            // ----------------------------------------------------------------------            // CASE2:            // 前置条件:当前TreeBin中 等待者线程 或者 写线程 都没有            // 条件成立:说明添加读锁成功            else if (U.compareAndSwapInt(this, LOCKSTATE, s,                                         s + READER)) {                TreeNode<K,V> r, p;                try {                    // 查询操作                    p = ((r = root) == null ? null :                         r.findTreeNode(h, k, null));                } finally {                    // w 表示等待者线程                    Thread w;                    // U.getAndAddInt(this, LOCKSTATE, -READER) == (READER|WAITER)                    // 1.当前线程查询红黑树结束,释放当前线程的读锁 就是让 lockstate 值 - 4                    // (READER|WAITER) = 0110 => 表示当前只有一个线程在读,且“有一个线程在等待”                    // 当前读线程为 TreeBin中的最后一个读线程。                    // 2.(w = waiter) != null 说明有一个写线程在等待读操作全部结束。                    if (U.getAndAddInt(this, LOCKSTATE, -READER) ==                        (READER|WAITER) && (w = waiter) != null)                        // 使用unpark 让 写线程 恢复运行状态。                        LockSupport.unpark(w);                }                return p;            }        }    }    return null;}

以上是“ConcurrentHashMap: 红黑树代理类的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网精选频道!

--结束END--

本文标题: ConcurrentHashMap: 红黑树代理类的示例分析

本文链接: https://lsjlt.com/news/279984.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • ConcurrentHashMap: 红黑树代理类的示例分析
    小编给大家分享一下ConcurrentHashMap: 红黑树代理类的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1、TreeBin内部类分析TreeB...
    99+
    2023-06-15
  • 解析ConcurrentHashMap: 红黑树的代理类(TreeBin)
    目录1、TreeBin内部类分析2、treeifyBin方法分析3、find方法分析总结前一章是get、remove方法分析,喜欢的朋友点击查看。本篇为ConcurrentHashM...
    99+
    2024-04-02
  • C++中红黑树的示例分析
    这篇文章将为大家详细讲解有关C++中红黑树的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。红黑树红黑树的概念红黑树的概念 红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以...
    99+
    2023-06-29
  • C++数据结构红黑树的示例分析
    这篇文章给大家分享的是有关C++数据结构红黑树的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。概念和性质红黑树的概念: 红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或...
    99+
    2023-06-29
  • Java数据结构之红黑树的示例分析
    小编给大家分享一下Java数据结构之红黑树的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、红黑树所处数据结构的位置:在JDK源码中, 有treeMap...
    99+
    2023-05-30
    java
  • 基于红黑树插入操作原理及java实现的示例分析
    这篇文章主要介绍基于红黑树插入操作原理及java实现的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!红黑树是一种二叉平衡查找树,每个结点上有一个存储位来表示结点的颜色,可以是RED或BLACK。红黑树具有以下...
    99+
    2023-05-30
    java
  • C++ STL容器中红黑树部分模拟实现的示例分析
    这篇文章主要介绍了C++ STL容器中红黑树部分模拟实现的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、红黑树的概念红黑树(Red Black Tree...
    99+
    2023-06-21
  • C语言实现手写红黑树的示例代码
    目录前沿红黑树代码测试前沿 写C的红黑树前建议先看我博客这篇文章Java-红黑树 主要看原理 红黑树代码 #ifndef STUDY_RBTREE_H #define ...
    99+
    2024-04-02
  • Java源码ConcurrentHashMap的示例分析
    小编给大家分享一下Java源码ConcurrentHashMap的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!一、记录形式打算直接把过程写在源码中,会按序进行注释,查阅的时候可以按序号只看注释部分二、Concur...
    99+
    2023-06-15
  • concurrenthashmap中size方法原理的示例分析
    小编给大家分享一下concurrenthashmap中size方法原理的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!concurrenthashmap的size方法原理同上,这也是同一个面试的时候别人问的,我只是...
    99+
    2023-06-29
  • ConcurrentHashMap: get、remove方法的示例分析
    小编给大家分享一下ConcurrentHashMap: get、remove方法的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!1、get方法get方法:获取元素,根据目标key所在桶的第一个元素的不同采用不同的方...
    99+
    2023-06-15
  • Java源码解析之ConcurrentHashMap的示例分析
    小编给大家分享一下Java源码解析之ConcurrentHashMap的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!早期 ConcurrentHashMap,其实现是基于:分离锁,也就是将内部进行分段(Segme...
    99+
    2023-06-15
  • C语言实现手写Map(数组+链表+红黑树)的示例代码
    目录要求结构红黑树和链表转换策略hash使用要求 需要准备数组集合(List) 数据结构 需要准备单向链表(Linked) 数据结构 需要准备红黑树(Rbtree)数据结构 需要准备...
    99+
    2024-04-02
  • 分析红黑树在C++云计算服务中的应用模式
    红黑树是一种自平衡二叉查找树,它在C++云计算服务中有着广泛的应用模式。在云计算服务中,红黑树通常被用作数据结构的基础,用于实现高效...
    99+
    2024-04-26
    C++
  • 红黑树的原理及特点及其在Python中的代码实现
    红黑树和B+树一样,是平衡二叉搜索树。红黑树每个节点都是有颜色的,要么是红色,要么黑色,但树的根是黑色,最底部的叶也是黑色的。还需要注意的是,红黑树任何节点到叶的直接路径包含相同数量的黑色节点。 红黑树如何保持自平衡的特性? ...
    99+
    2024-01-23
  • 分析C++中红黑树的时间复杂度和空间复杂度
    红黑树是一种自平衡的二叉搜索树,它具有以下特点: 每个节点要么是红色,要么是黑色。 根节点是黑色。 每个叶子节点(NIL节点)是黑...
    99+
    2024-04-26
    C++
  • python实现决策树分类算法代码示例
    目录前置信息1、决策树2、样本数据策树分类算法1、构建数据集2、数据集信息熵3、信息增益4、构造决策树5、实例化构造决策树6、测试样本分类后置信息:绘制决策树代码总结前置信息 1、决...
    99+
    2024-04-02
  • mysql树状查询的示例分析
    这篇文章主要为大家展示了“mysql树状查询的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“mysql树状查询的示例分析”这篇文章吧。--创建表dro&...
    99+
    2024-04-02
  • JavaScript之树结构的示例分析
    这篇文章主要介绍了JavaScript之树结构的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。二叉树--概念--二叉树是一种树形结构...
    99+
    2024-04-02
  • 镜像二叉树的示例分析
    镜像二叉树的示例分析,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。算法这个东西很难,纵使你了解了其中的逻辑,用代码写出来仍然不是一件容易的事,内部有太多的细节需...
    99+
    2023-06-04
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作