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);ブロックすることがわかりました。しかし、ドキュメントによると、「ConcurrentHashMap」は検索操作でブロックされません。何が問題なのかわかりません。mNameCachemNameCache.put(callId, nameHolder);

4

2 に答える 2

3

私の知る限り、それはブロックされるかもしれません。

(ConcurrentHashMap の理解が間違っている場合は修正してください)。

ConcurrentHashMap の全体的な考え方は、ハッシュ テーブルを格納する 1 つの大きな配列を持ち、全員がテーブル全体をロックする代わりに、パーティションに分割されていることです (ConcurrentHashMap のソース コードで内部クラス "Segment" を確認できます)。「競合がない」場合は、異なるパーティションに対して読み取りまたは書き込みを行っている場合のみです。

他の回答で引用されている Stephen C のソース コードをよく見てlock()ください。2 つのスレッドが同じパーティションにアクセスしている場合、セグメントをロックして作業を行います。unlock()readValueUnderLock()

したがって、UI スレッドがput同じキー (または同じセグメント内の別のキー) に接続している場合、終了するまでブロックされます。get()

ただし、質問で話している意味ではブロッキングではありません。アクセス (get/put など) の期間だけブロックし、操作が完了するとロックが解除されます。

于 2012-09-17T06:25:36.870 に答える
2

簡単な答えはノーです。あなたが私たちに伝えていないことが他にない限り、get呼び出しは 1 マイクロ秒程度以上ブロックされません。

メソッドとそのヘルパー メソッドのソース コードは次の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」。)

于 2012-09-17T06:00:24.907 に答える