- 浏览: 550137 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
hdblocal_:
为什么messageReceived之后,再encode,有点 ...
MINA框架使用总结 -
andey007518:
MINA框架使用总结 -
ymm8505:
我自己的理解 CopyOnWriteArrayList 这个 ...
ArrayList遍历的同时删除 -
spring_springmvc:
可以参考最新的文档:如何在eclipse jee中检出项目并转 ...
Eclipse快捷键-方便查找 -
netwelfare:
文章讲解的不够详细,ArrayList在遍历的同时如果去删除或 ...
ArrayList遍历的同时删除
最近研究了一下 ConcurrentHashMap中源码发现jdk中的remove方法实现有点问题.
同时参考了文章: http://www.iteye.com/topic/344876
以下是对此文章的一段评述的引用:
V get(Object key, int hash) { if (count != 0) { // read-volatile HashEntry<K,V> e = getFirst(hash); while (e != null) { if (e.hash == hash && key.equals(e.key)) { V v = e.value; if (v != null) return v; return readValueUnderLock(e); // recheck } e = e.next; } } return null; }
marlonyao 写道
get操作不需要锁。第一步是访问count变量,这是一个volatile变量,由于所有的修改操作在进行结构修改时都会在最后一步写count变量,通过这种机制保证get操作能够得到几乎最新的结构更新。对于非结构更新,也就是结点值的改变,由于HashEntry的value变量是volatile的,也能保证读取到最新的值。接下来就是对hash链进行遍历找到要获取的结点,如果没有找到,直接访回null。对hash链进行遍历不需要加锁的原因在于链指针next是final的。但是头指针却不是final的,这是通过getFirst(hash)方法返回,也就是存在table数组中的值。这使得getFirst(hash)可能返回过时的头结点,例如,当执行get方法时,刚执行完getFirst(hash)之后,另一个线程执行了删除操作并更新头结点,这就导致get方法中返回的头结点不是最新的。这是可以允许,通过对count变量的协调机制,get能读取到几乎最新的数据,虽然可能不是最新的。要得到最新的数据,只有采用完全的同步。
事实上这样也存在一定可能的脏读,同时参考文章:
http://www.ibm.com/developerworks/java/library/j-jtp08223
里面对remove的写法我觉得非常合理:
protected Object remove(Object key, Object value) { /* Find the entry, then 1. Set value field to null, to force get() to retry 2. Rebuild the list without this entry. All entries following removed node can stay in list, but all preceding ones need to be cloned. Traversals rely on this strategy to ensure that elements will not be repeated during iteration. */ int hash = hash(key); Segment seg = segments[hash & SEGMENT_MASK]; synchronized(seg) { Entry[] tab = table; int index = hash & (tab.length-1); Entry first = tab[index]; Entry e = first; for (;;) { if (e == null) return null; if (e.hash == hash && eq(key, e.key)) break; e = e.next; } Object oldValue = e.value; if (value != null && !value.equals(oldValue)) return null; e.value = null;/这里很关键的一个设置但是可惜我们的jdk中没有此步骤,难道是sun故意的? Entry head = e.next; for (Entry p = first; p != e; p = p.next) head = new Entry(p.hash, p.key, p.value, head); tab[index] = head; seg.count--; return oldValue; } }
return readValueUnderLock(e); // recheck 方法同是可以防止e.value=null的问题
下面是我自己对jdk代码的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; // All entries following removed node can stay // in list, but all preceding ones need to be // cloned. ++modCount; e.value=null;添加此行代码 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; // write-volatile } } return oldValue; } finally { unlock(); } }
参考文章:
http://www.iteye.com/topic/344876
http://www.ibm.com/developerworks/java/library/j-jtp08223
发表评论
-
为何在使用CMS gc算法时会出现连续两次full gc
2011-09-01 11:04 4919现象: jstat -gcutil pid 1000观察到 ... -
配置filter拦截forward之类的内部转发
2011-02-18 17:19 5959在servlet-2.3中,Filter会过滤一切请求,包括服 ... -
request.getRequestURI 与request.getServletPath() 区别
2011-02-16 19:38 7815路径:resin/webapps/my_proj/test/r ... -
搭建Android开发环境
2010-04-05 23:22 1511在eclipse上安装Android 1.安装eclipse ... -
IoServer源代码阅读笔记
2009-08-23 21:57 2114NIO:写事件要尽量早的被注销. 1,IOServer用一 ... -
一个webapp目录下部署多个web应用
2009-08-21 10:34 2122在同一个resin下的webapp目录部署多个web应用,发现 ... -
java 的深度克隆
2009-07-01 20:07 1743只有实现了cloneable接口才算是真正的深度克隆. 在复 ... -
try finally return
2009-03-20 19:21 1212class Entry { ... -
String和==号的问题
2009-03-09 19:45 1198String name = "you" ... -
Bit数组
2009-01-20 18:56 2856public class BitArray{//用byte数组 ... -
关于Java占用内存的研究 (转载请注明作者zms)
2009-01-20 15:28 2935版权声明:转载时请以 ... -
几种通讯协议的比较
2009-01-20 15:26 5318一、综述 本文比较了RMI ... -
java基础知识总结
2009-01-06 00:50 2808http://wiki.caucho.com/Hessian_ ... -
Java基础-关于session的详细解释
2008-12-01 23:49 1312一、术语session 在我的经验里,session这个词 ... -
关于大量缓存对象回收的思考
2008-12-01 15:34 2635前几天面试,被问到了一个问题,如果当前有数亿条记录,但是缓存最 ... -
java 快速排序demo
2008-11-29 19:52 2017快速排序算法思想如下,先选取一个元素作为基准,然后根据这个基准 ... -
java 实现简单的文件拷贝
2008-11-26 17:36 6238昨天面试,面试官要我在黑板上写个java文件复制的代码,但是一 ... -
HashMap的遍历效率讨论
2008-11-26 11:31 3659经常遇到对HashMap中的key和value值对的遍历操作 ... -
Java ArrayList 实现
2008-11-25 23:02 3720ArrayList是List接口的一个可变长数组实现。实现了 ... -
c与java通信时数值类型存储的顺序问题
2008-08-09 15:19 3366Byte:一个字节,标记为byte 0 Word:二个字节,从 ...
相关推荐
computeIfAbsent方法会初始化一个ReservationNode来占位,它会等待计算完毕后替换当前的占位对象。 这时候ConcurrentHashMap达到容量扩容而忽略了ReservationNode情况,调用put的时候在synchronized(f)没有对...
主要介绍了JDK1.8中ConcurrentHashMap中computeIfAbsent死循环bug,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
高薪程序员面试题精讲系列49之说说ConcurrentHashMap#put方法的源码及数。。。.pdf,这是一份不错的文件
java源码剖析-ConcurrentHashMap
ConcurrentHashMap源码剖析
下面小编就为大家带来一篇基于Java并发容器ConcurrentHashMap#put方法解析。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
java7-8中的 HashMap和ConcurrentHashMap全解析
Java利用ConcurrentHashMap实现本地缓存demo; 基本功能有缓存有效期、缓存最大数、缓存存入记录、清理线程、过期算法删除缓存、LRU算法删除、获取缓存值等功能。 复制到本地项目的时候,记得改包路径哦~
源码分析见我博文:http://blog.csdn.net/wabiaozia/article/details/50684556
ConcurrentHashMap具体是怎么实现线程安全的呢,肯定不可能是每个方法加synchronized,那样就变成了HashTable。
ConcurrentHashMap可以做到读取数据不加锁,并且其内部的结构可以让其在进行写操作的时候能够将锁的粒度保持地尽量地小,允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的...
java7-8中的 HashMap和ConcurrentHashMap全解析 如果你想了解底层的逻辑就来看看吧
解析concurrenthashmap的源码,学习多线程的思想
本文将结合Java内存模型,分析JDK源代码,探索ConcurrentHashMap高并发的具体实现机制,包括其在JDK中的定义和结构、并发存取、重哈希和跨段操作,并着重剖析了ConcurrentHashMap读操作不需要加锁和分段锁机制的内在...
程序员面试加薪必备_ConcurrentHashMap底层原理与源码分析深入详解
java本地缓存ConcurrentHashMap
主要介绍了Java中遍历ConcurrentHashMap的四种方式详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
ConcurrentHashMap之实现细节
ConcurrentHashMap是一个线程安全的HashTable,它的主要功能是提供了一组和HashTable功能相同但是线程安全的方法。ConcurrentHashMap可以做到读取数据不加锁,并且其内部的结构可以让其在进行写操作的时候能够将锁的...
concurrenthashmap1.7的源码分析