专栏首页人生得意须尽欢get的过程中另一个线程删除一个entry
原创

get的过程中另一个线程删除一个entry

get的过程中另一个线程删除一个entry

  假设我们的链表元素是:e1-> e2 -> e3 -> e4 我们要删除 e3这个entry   因为HashEntry中next的不可变,所以我们无法直接把e2的next指向e4,而是将要删除的节点之前的节点复制一份,形成新的链表。它的实现大致如下图所示:

  注意:最后才将数组中对应桶位置的链表替换为新链表(也就是在最后一步替换之前,tab[i]指向的始终是删除之前的链表,详细看下面的remove方法)。   如果我们get的也恰巧是e3,可能我们顺着链表刚找到e1,这时另一个线程就执行了删除e3的操作,而我们线程还会继续沿着旧的链表找到e3返回,这时候可能看到被删除的数据,但是在高并发环境下,这种影响是很小的。

remove方法

    V remove(Object key, int hash, Object value) { 
           lock();         // 加锁
           try{ 
               int c = count - 1; 
               HashEntry<K,V>[] tab = table; 
               int index = hash & (tab.length - 1); 
               HashEntry<K,V> first = tab[index]; 
               HashEntry<K,V> e = first; 
               while(e != null&& (e.hash != hash || !key.equals(e.key))) 
                   e = e.next; 
 
               V oldValue = null; 
               if(e != null) { 
                   V v = e.value; 
                   if(value == null|| value.equals(v)) { // 找到要删除的节点
                       oldValue = v; 
                       ++modCount; 
                       // 所有处于待删除节点之后的节点原样保留在链表中
                       // 所有处于待删除节点之前的节点被克隆(其实是把所有值取出来放到一个新的HashEntry对象中)到新链表中
                       HashEntry<K,V> newFirst = e.next;// 待删节点的后继结点
                       for(HashEntry<K,V> p = first; p != e; p = p.next) 
                           newFirst = new HashEntry<K,V>(p.key, p.hash,  newFirst, p.value); 

                       // 新的头结点是原链表中,删除节点之前的那个节点
                       tab[index] = newFirst; 
                       count = c;      // 写 count 变量
                   } 
               } 
               return oldValue; 
           } finally{ 
               unlock();               // 解锁
           } 
       }

  和 get 操作一样,首先根据散列码找到具体的链表;然后遍历这个链表找到要删除的节点;最后把待删除节点之后的所有节点原样保留在新链表中,把待删除节点之前的每个节点克隆(其实是把所有值取出来放到一个新的HashEntry对象中)到新链表中;最后才将数组中对应桶位置的链表替换为新链表(也就是在替换之前,get的始终是删除之前的链表)。   下面通过图例来说明 remove 操作。假设写线程执行 remove 操作,要删除链表的 C 节点,另一个读线程同时正在遍历这个链表。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • get的过程中另一个线程恰好新增entry

    ConcurrentHashMap完全允许多个读操作并发进行,读操作并不需要加锁。关键是用 HashEntry 对象的不变性来降低读操作对加锁的需求。只是判断获...

    用户7365393
  • java中一个子线程如何通过interrupt手段来停止另外一个子线程

    public void setSilblingThread1(Thread t1) {

    马克java社区
  • C#中线程的使用(一):通过委托开启一个线程

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明...

    bering
  • ConcurrentHashMap原理分析

    ConcurrentHashMap是Java5中新增加的一个线程安全的Map集合,可以用来替代HashTable。对于ConcurrentHashMap是如何提...

    一觉睡到小时候
  • 一个NB项目的上线过程

    纯洁的微笑
  • vc++ 在程序中运行另一个程序的方法

    在vc++ 程序中运行另一个程序的方法有三个: WinExec(),ShellExcute()和CreateProcess() 三个SDK函数: WinExec...

    用户1198337
  • HashTable原理和底层实现

    上次讨论了HashMap的结构,原理和实现,本文来对Map家族的另外一个常用集合HashTable进行介绍。HashTable和HashMap两种集合非常相似,...

    用户6182664
  • 记一次删除Git记录中的大文件的过程

    一头小山猪
  • java中请给出了一个主线程要join一个子线程的例子

    马克-to-win:join的意思就是本线程停下来,等着另外一个线程完事,之后执行本线程的下一句话。(感觉有点像过去张三等着李四,等到后join在一起一块继续走...

    马克java社区
  • 面试又被问懵了吗?不如把ThreadLocal拆开了揉碎看看

    所谓并发,就是有限资源需要应对远超资源的访问。解决问题的方法,要么增加资源应对访问;要么增加资源的利用率。 所以,相信这年头做开发的多多少少,都会那么几个“线程...

    Java程序猿阿谷
  • 快速掌握并发编程---深入学习ThreadLocal

    考试题只有一套,老师把考试题打印出多份,发给每位考生,然后考生各自写各自的试卷。考生之间不能相互交头接耳(会当做作弊)。各自写出来的答案不会影响他人的分数。

    田维常
  • ThreadLocal解析

    这个类,好早就有了,JDK1.2就出现了。有时也会用一用,但他的作用是什么,很难表达了,难以表达,不能形成文字,说明了解的深度不够。

    码农戏码
  • 深入理解ThreadLocal

    在每个线程Thread内部有一个ThreadLocalMap,这是用来存储实际的变量副本的,键值key为当前ThreadLocal变量,value为变量副本。初...

    java达人
  • 大话 ThreadLocal

    该类提供了线程本地变量。该变量不同于普通的副本,因为访问这个变量(通过 get 或 set 方法)的每个线程都是自己独立初始化该变量的。 ThreadLoca...

    tomas家的小拨浪鼓
  • ThreadLocal全面解析

    ThreadLocal类保证了线程内部的变量在多线程环境下相对于其他线程是不可见的。

    虞大大
  • 疯狂Java笔记之常见java集合的实现细节

    首先Set是一种集合元素无序,不可重复的集合。而Map则代表一种有多个key-value对组成的集合,Map集合类似于传统的关联数据。看起来他们没哟什么关联,实...

    HelloJack
  • MyBatis Generator使用过程中踩过的一个坑

    使用的是mall-tiny-02的代码,代码地址:https://github.com/macrozheng/mall-learning/tree/master...

    macrozheng
  • ThreadLocal内存泄漏问题及如何解决

    神秘的寇先森
  • java中一个子线程如何通过interrupt手段来停止主线程

    ThreadMark_to_win st = new ThreadMark_to_win();

    马克java社区

扫码关注云+社区

领取腾讯云代金券