IFULEYOU49
IFULEYOU49
2013-04-08 08:54

concurrentHashMap是线程安全且强一致性的吗?

已采纳

看了文档,但是不是很明白,这个类可以在不阻塞线程的情况下提供线程安全的并发写,但是他没有对读进行同步,那么,假如读和写发生在同一个元素的时候,怎么办?这时候不做同步,那么数据肯定是脏的啊?还是我理解有错,大家都怎么使用这个类咧

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

8条回答

  • jinnianshilongnian jinnianshilongnian 8年前

    说白了ConcurrentHashMap也是加锁的 但是不是全局锁 而是 分块锁(对桶里的数据分块 按块加锁 提高并发)

    点赞 2 评论 复制链接分享
  • iteye_7251 iteye_7251 8年前

    单独的读写操作(get,put,putIfAbsent...)是完全线程安全且一致的,但是迭代时候则不是强一致的,迭代所遍历的不是迭代时刻的快照,而是各个segement的真是数据,所以迭代期间如有数据发生变更,如果变更的是已经遍历的segement则迭代过程不再感知这个变化,但如果变化发生在未遍历的segement,则本次迭代会感知到这个元素。另外一个基本常识,任意的组合操作,比如先get, 然后put,则不能保证强一致。此外这个类还有个特点,迭代过程中即使元素被修改,也不会抛出异常,其他一些集合则会抛出ConcurrentModificationException

    点赞 2 评论 复制链接分享
  • wanglong1615 wanglong1615 7年前

    如读和写发生在同一个元素的时候,怎么办?这时候不做同步,那么数据肯定是脏的啊。

    你理解的脏数据是有问题的,脏数据是指消费和生产的数据不一致,好比存钱和取钱,最后发现钱少了或钱多了,这就是脏数据。
    而你描述的顶多算幻读,我在12:00打钱到你卡上,你12:05分才看到。幻读在任何系统都会出现,如果你一定不想有幻读,那么只有牺牲效率为代价。
    这方面跟数据库的事务隔离级别就点类似。

    点赞 评论 复制链接分享
  • a1000005aa a1000005aa 8年前

    ConcurrentHashMap对K/V的读写都是加锁的,是一个可重入锁(ReenTrantLock),当然这是一个Segment(片段锁),只会锁定某一个K/V,基于CAS调度,也就是与CPU的直接打交道的,使用的是NonfairSync,所以能保证最大的吞吐量.

    JDK中的任何类的线程安全只针对于类内部,比如你执行如下代码
    map.put(1,1)//@1
    int a = map.get(1)
    map.put(1,2)//@2
    int b = map.get(1)
    a==b? true: false
    如果是单线程,那么返回的是false,如果是多线程环境,那么你要注意了.
    当线程A执行完@1的时候,可能CPU调度的时候[轮到线程B],线程B执行完@2,那么a的值就为2
    所以在多线程环境,同步是由程序员来控制的.至于你说的强一致性,就看你自己的理解了

    点赞 评论 复制链接分享
  • ticmy 龙四 8年前

    检索会影响最近[color=red]完成的[/color] 更新操作的结果

    所谓完成的,就是从put方法返回了

    点赞 评论 复制链接分享
  • iteye_6961 iteye_6961 8年前

    ConcurrentHashMap 将 map中数据通过hash 散列到32个Segment 中,Segment 是 ConcurrentHashMap 一个内部类,他继承了ReentrantLock ,ConcurrentHashMap 将锁进行分化到每一个Segment中,只有对同一个Segment 元素的读写时 才会阻塞,否则是无阻塞的,这样就大大的提高了并发的执行速度。

    V get(Object key, int hash) {
    if (count != 0) { // read-volatile
    HashEntry 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;

    V put(K key, int hash, V value, boolean onlyIfAbsent) {
    lock();
    try {
    int c = count;
    if (c++ > threshold) // ensure capacity
    rehash();
    HashEntry[] tab = table;
    int index = hash & (tab.length - 1);
    HashEntry first = tab[index];
    HashEntry e = first;
    while (e != null && (e.hash != hash || !key.equals(e.key)))
    e = e.next;

                V oldValue;
                if (e != null) {
                    oldValue = e.value;
                    if (!onlyIfAbsent)
                        e.value = value;
                }
                else {
                    oldValue = null;
                    ++modCount;
                    tab[index] = new HashEntry<K,V>(key, hash, first, value);
                    count = c; // write-volatile
                }
                return oldValue;
            } finally {
                unlock();
            }
        }
    

    get中的readValueUnderLock 和 put 都是互斥的 所以是安全的

    点赞 评论 复制链接分享
  • iteye_18669 iteye_18669 8年前

    [code="java"]
    /**

    • ConcurrentHashMap list entry. Note that this is never exported
    • out as a user-visible Map.Entry. *
    • Because the value field is volatile, not final, it is legal wrt
    • the Java Memory Model for an unsynchronized reader to see null
    • instead of initial value when read via a data race. Although a
    • reordering leading to this is not likely to ever actually
    • occur, the Segment.readValueUnderLock method is used as a
    • backup in case a null (pre-initialized) value is ever seen in
    • an unsynchronized access method. */ static final class HashEntry { final K key; final int hash; volatile V value; // <-- volatile final HashEntry next; }[/code]

    按照我的理解,volatile可以保证一个线程总是能看到最后一个线程写入的数据,HashEntry的构造函数也没有escape this,这里readValueUnderLock只是用来backup的吧,实际上并不太可能会出现为null的情况

    参考资料
    http://stackoverflow.com/questions/12740844/why-get-method-in-concurrenthashmap-is-blocking
    http://jsr166-concurrency.10961.n7.nabble.com/Numa-and-ReentrantLock-td5630.html
    http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#finalRight

    点赞 评论 复制链接分享
  • ll89308839 ll89308839 8年前

    [code="java"] V get(Object key, int hash) {
    if (count != 0) { // read-volatile
    HashEntry 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;
    }[/code]

    在写的时候,是不读就为null

    在读的时候时,有同步锁
    [code="java"]
    V readValueUnderLock(HashEntry e) {
    lock();
    try {
    return e.value;
    } finally {
    unlock();
    }
    }
    [/code]

    点赞 评论 复制链接分享

相关推荐