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

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

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

4

2 回答 2

3

AFAIK,它可能会阻塞。

(如果我对 ConcurrentHashMap 的理解有误,请纠正我)。

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

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

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

但是,从您在问题中谈论的意义上说,它并没有阻塞。它只在访问期间阻塞(get/put 等),一旦操作完成,锁就会被释放。

于 2012-09-17T06:25:36.870 回答
2

简单回答是不。除非您没有告诉我们其他事情,否则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

(如果链接断开,谷歌“ConcurrentHashMap android source”。)

于 2012-09-17T06:00:24.907 回答