Java Eşzamanlı Hashmap initTable () Neden try / nihayet engelleniyor?
Ş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
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ı.
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 .