繁体   English   中英

获取块 ConcurrentHashMap 吗?

[英]Does get block ConcurrentHashMap?

片段 1:

private void startLoadingName() {
    for (ConcurrentHashMap.Entry<TextView, Long> entry : mPendingNameRequest.entrySet()) {
        long callId = (Long)entry.getValue();
        NameHolder nameHolder = mNameCache.get(callId);
        nameHolder.name = QueryUtils.loadNameFromDb(mContext, callId);
        nameHolder.status = NameHolder.LOADED;
        // mNameCache is a ConcurrentHashMap
        mNameCache.put(callId, nameHolder);

        updateContactCachedName(callId, nameHolder);
    }

    GsItemLoader.this.sendEmptyMessage(MESSAGE_SET_NAME);
}

此代码段在 UI 线程以外的线程上运行。 每次执行时,ListView 滚动总是变慢,所以代码段中一定有什么东西阻塞了 UI 线程。

我发现NameHolder nameHolder = mNameCache.get(callId); 将阻塞mNameCache直到mNameCache.put(callId, nameHolder); . 但是文档说“ConcurrentHashMap”不会阻止检索操作。 我不知道出了什么问题。

AFAIK,它可以阻止。

(如果我在ConcurrentHashMap中的理解错误,请纠正我)。

ConcurrentHashMap的整个想法是,有一个大数组存储哈希表,每个人都锁定整个表,它被分成几个分区(你可以在ConcurrentHashMap的源代码中看到内部类“Segment”)。 只有当您正在读取或写入不同的分区时,存在“无争用”的情况。

看看在另一个答案中引用的源代码Stephen C,你可以在readValueUnderLock()看到lock()unlock() readValueUnderLock() 如果两个线程正在访问同一个分区,它将锁定该段并完成其工作。

因此,如果你的UI线程被put相同的键(或同一段中的其他键),它将阻塞,直到你完成你的get()

但是,在您提出的问题中,它并没有阻止。 它仅在访问(get / put等)期间阻塞,并且一旦操作完成就释放锁。

简单回答是不。 除非您没有告诉我们其他内容,否则get呼叫将不会阻止超过一微秒左右。

get方法的源代码及其辅助方法如下所示。 正如您所看到的,大部分工作都是在没有任何锁定的情况下完成的。 最终获取条目值是在锁定下完成的,但锁定将几乎立即释放...在finally块中。

可以肯定地说, get()调用不是导致问题的原因。


    /**
     * Reads value field of an entry under lock. Called if value
     * field ever appears to be null. This is possible only if a
     * compiler happens to reorder a HashEntry initialization with
     * its table assignment, which is legal under memory model
     * but is not known to ever occur.
     */
    V readValueUnderLock(HashEntry<K,V> e) {
        lock();
        try {
            return e.value;
        } finally {
            unlock();
        }
    }

    /* Specialized implementations of map methods */

    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;
    }

资料来源: http//www.java2s.com/Open-Source/Android/android-core/platform-libcore/java/util/concurrent/ConcurrentHashMap.java.htm

(如果链接中断,Google“ConcurrentHashMap android source”。)

我检查了代码 java ConcurrentHashMap JDK 17。get() 不锁定 Bucket。 这意味着您可以在存储桶写入(放入或删除)期间读取存储桶。

但是存储桶在写入期间被锁定。 这意味着只有一个线程可以同时写入更改存储桶。

所以,并发读/写时有以下三种情况:

案例 1:先读后写。 所以读取访问旧存储桶

case 2 : read after write 包括2种情况:

   case 2.1: read access old bucket if write has not finished changing during read access

   case 2.2: read access new bucket if write has finished changing during read access

注意读比写快。 所以案例 2.1可能会发生

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM