简体   繁体   English

获取块 ConcurrentHashMap 吗?

[英]Does get block ConcurrentHashMap?

Snippet 1:片段 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);
}

This snippet is run on a thread other than the UI thread.此代码段在 UI 线程以外的线程上运行。 Every time it executes, the ListView scroll always slows down, so there must be something in the snippet that blocks the UI thread.每次执行时,ListView 滚动总是变慢,所以代码段中一定有什么东西阻塞了 UI 线程。

I found that NameHolder nameHolder = mNameCache.get(callId);我发现NameHolder nameHolder = mNameCache.get(callId); will block mNameCache until mNameCache.put(callId, nameHolder);将阻塞mNameCache直到mNameCache.put(callId, nameHolder); . . But the docs says 'ConcurrentHashMap' won't block in retrieval operations.但是文档说“ConcurrentHashMap”不会阻止检索操作。 I can't figure out what's going wrong.我不知道出了什么问题。

AFAIK, it MAY block. AFAIK,它可以阻止。

(Please correct me if my understanding in ConcurrentHashMap is wrong). (如果我在ConcurrentHashMap中的理解错误,请纠正我)。

The whole idea of ConcurrentHashMap is, instead having one big array storing the hash table and everyone is locking the whole table, it is in splitted into partitions (you can see the inner class "Segment" in ConcurrentHashMap's source code). ConcurrentHashMap的整个想法是,有一个大数组存储哈希表,每个人都锁定整个表,它被分成几个分区(你可以在ConcurrentHashMap的源代码中看到内部类“Segment”)。 The case that there is "no contention" is only when you are reading or writing to different partitions. 只有当您正在读取或写入不同的分区时,存在“无争用”的情况。

Look close to the source code Stephen C quoted in the other answer, you can see lock() and unlock() in readValueUnderLock() . 看看在另一个答案中引用的源代码Stephen C,你可以在readValueUnderLock()看到lock()unlock() readValueUnderLock() If two thread is accessing same partition, it will lock the segment and do its work. 如果两个线程正在访问同一个分区,它将锁定该段并完成其工作。

Therefore, if your UI thread is put ting to the same key (or other key in same segment), it will block until you finish your get() 因此,如果你的UI线程被put相同的键(或同一段中的其他键),它将阻塞,直到你完成你的get()

However, it is not blocking in the sense you are talking about in your question. 但是,在您提出的问题中,它并没有阻止。 It only blocks for the period of accessing (get/put etc), and lock is released once the operation is finished. 它仅在访问(get / put等)期间阻塞,并且一旦操作完成就释放锁。

The simple answer is no. 简单回答是不。 Unless there is something else you are not telling us, the get call won't block for longer than a microsecond or so. 除非您没有告诉我们其他内容,否则get呼叫将不会阻止超过一微秒左右。

The source code for the get method and its helper method are below. get方法的源代码及其辅助方法如下所示。 As you can see, most of the work is done without any locks whatsoever. 正如您所看到的,大部分工作都是在没有任何锁定的情况下完成的。 The final fetch of the entry value is done under a lock, but the lock will be released almost instantly ... in a finally block. 最终获取条目值是在锁定下完成的,但锁定将几乎立即释放...在finally块中。

It is safe to say that the get() call is not the cause of your problem. 可以肯定地说, 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;
    }

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

(If the link breaks, Google "ConcurrentHashMap android source".) (如果链接中断,Google“ConcurrentHashMap android source”。)

I checked code java ConcurrentHashMap JDK 17. get() doesn't lock Bucket.我检查了代码 java ConcurrentHashMap JDK 17。get() 不锁定 Bucket。 it means that you can read Bucket during The bucket is writing (put or remove).这意味着您可以在存储桶写入(放入或删除)期间读取存储桶。

But bucket is locked during write.但是存储桶在写入期间被锁定。 It means that only one thread can write to change bucket at the same time.这意味着只有一个线程可以同时写入更改存储桶。

So, there are three case when read/write concurrently:所以,并发读/写时有以下三种情况:

case 1: read before write.案例 1:先读后写。 so read access old bucket所以读取访问旧存储桶

case 2 : read after write include 2 cases: 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

notice that read is more faster than write.注意读比写快。 so case 2.1 can happen所以案例 2.1可能会发生

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

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