Java Eşzamanlı Hashmap initTable () Neden try / nihayet engelleniyor?

Aug 29 2020

Şu koda bakıyordum ( buradan kaynaklanmıştır ) '

/**
 * Initializes table, using the size recorded in sizeCtl.
 */
private final Node<K,V>[] initTable() {
    Node<K,V>[] tab; int sc;
    while ((tab = table) == null || tab.length == 0) {
        if ((sc = sizeCtl) < 0)
            Thread.yield(); // lost initialization race; just spin
        else if (U.compareAndSetInt(this, SIZECTL, sc, -1)) {
            try {
                if ((tab = table) == null || tab.length == 0) {
                    int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
                    @SuppressWarnings("unchecked")
                    Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                    table = tab = nt;
                    sc = n - (n >>> 2);
                }
            } finally {
                sizeCtl = sc;
            }
            break;
        }
    }
    return tab;
}

Birisi deneme bloğuna neden ihtiyaç olduğunu açıklayabilir mi?

Yanıtlar

3 rzwitserloot Aug 29 2020 at 20:31

kontrol edilmeyen istisnalar ve hatalar bir kavram olarak mevcuttur. .put()Bir ConcurrentHashMap'i çağırırsanız ve hafızanız gerçekten kısıtlıysa, bu harita bir dizi oluşturmaya çalışabilir ve bu çağrı OutOfMemoryError ile başarısız olabilir. Kod hala devam edecek (belki bunu yakalayan yakalama bloğunda) ve bu haritaya yapılan referanslar hala var olacak. Bundan sonra haritanın çökmesi ve sizeCtl'nin bozuk bir değeri olduğu için tamamen geçersiz kılınması biraz saçma olurdu.

Önemli olan, sizeCtldeğeri geri yükleyen son olarak bloktur . Bu, hangi iş parçacığının erişebileceğini yönetmek dahil olmak üzere çeşitli şeyler için kullanılır. Olmasaydı, diğer put çağrıları sonsuza kadar dönerdi.

Bunun alaka düzeyi (burada bir atılabilirliğin ne sıklıkla meydana geldiği gibi, 'denemek' ve 'nihayet'i kaldırmak ve sadece sizeCtl = sc;deneme / nihayet ek yükü olmadan bitmek ) düşüktür, ancak uygunsa oldukça alakalı.

Den-Jason Aug 29 2020 at 20:32

Bu bir çeşit muteks - ve çift kontrol kilidi.

ilk olarak

if ((sc = sizeCtl) < 0)
    Thread.yield(); // lost initialization race; just spin

sizeCtlmuteksi kontrol eder . Sıfırdan küçükse, başka biri kapmış demektir, bu yüzden biraz bekleriz.

Sıfır (veya daha fazla) ise, kilidi alma şansımız var. Dolayısıyla, Karşılaştırma ve Değiştirme işlemi gerçekleştirilir:

if (U.compareAndSetInt(this, SIZECTL, sc, -1)

Bu atomik bir işlemdir - eğer birinci ve ikinci kontrol arasında başka bir iş parçacığı yakalandıysa, ifalınmayacaktır.

CAS başarılı olursa, yöntem muteksi serbest bırakmaktan sorumlu hale gelir. Bu nedenle, bir istisnanın meydana gelip gelmediğine (örn. Yeni Düğümün atanmasında bellek yetersiz - veya haritaya uygulanabilen benzersiz bir kısıtlama olup olmadığına) bakılmaksızın try-finallymuteksin serbest bırakılmasını ( sizeCtlorijinal değerine sıfırlanmasını) sağlamak için kullanılır .