Java Concurrent Hashmap initTable () ทำไมต้องลอง / บล็อกในที่สุด
ฉันได้ดูรหัสต่อไปนี้ (มีที่มาจากที่นี่ ) '
/**
* 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;
}
มีใครสามารถอธิบายได้ว่าทำไมจึงต้องมีการลองบล็อก
คำตอบ
มีข้อยกเว้นและข้อผิดพลาดที่ไม่ได้ตรวจสอบเป็นแนวคิด หากคุณเรียก.put()ใช้ ConcurrentHashMap และคุณมีหน่วยความจำแน่นจริงแผนที่นั้นอาจพยายามสร้างอาร์เรย์และการเรียกนั้นอาจล้มเหลวด้วย OutOfMemoryError รหัสจะยังคงดำเนินต่อไป (ที่บล็อกการจับที่จับสิ่งนี้ได้) และการอ้างอิงถึงแผนที่นั้นยังคงมีอยู่ มันจะค่อนข้างแย่ถ้าหลังจากนั้นเกิดขึ้นแผนที่ขัดข้องและไม่ถูกต้องอย่างสมบูรณ์เนื่องจาก sizeCtl มีค่าเสีย
ประเด็นคือสุดท้ายบล็อกซึ่งจะคืนsizeCtlค่า สิ่งนี้ใช้สำหรับสิ่งต่างๆที่โดดเด่นรวมถึงการจัดการว่าเธรดใดสามารถเข้าถึงได้ หากไม่เป็นเช่นนั้นการโทรอื่น ๆ จะหมุนตลอดไป
ความเกี่ยวข้องของสิ่งนี้ (เช่นเดียวกับที่เกิดขึ้นที่นี่บ่อยเพียงใดเมื่อเทียบกับการลบ 'ลอง' และ 'ในที่สุด' และลงท้ายด้วยsizeCtl = sc;โดยไม่ต้องมีค่าใช้จ่ายเพิ่มเติมในการลอง / ในที่สุด) นั้นต่ำ แต่ถ้ามีความเกี่ยวข้อง มันค่อนข้างเกี่ยวข้อง
มันคือ mutex ชนิดหนึ่งและตรวจสอบการล็อกอีกครั้ง
ประการแรก
if ((sc = sizeCtl) < 0)
Thread.yield(); // lost initialization race; just spin
ตรวจสอบsizeCtlmutex ถ้ามันน้อยกว่าศูนย์แสดงว่ามีคนอื่นคว้าไปได้ดังนั้นเราก็รอสักครู่
หากเป็นศูนย์ (หรือมากกว่า) โอกาสที่เราจะได้รับการล็อค ดังนั้นการเปรียบเทียบและสลับจึงดำเนินการ:
if (U.compareAndSetInt(this, SIZECTL, sc, -1)
นี่คือการทำงานของอะตอม - หากเธรดอื่นจับมันระหว่างการตรวจสอบครั้งแรกและครั้งที่สองifจะไม่ถูกนำมาใช้
หาก CAS ประสบความสำเร็จวิธีนี้จะต้องรับผิดชอบในการปล่อย mutex ดังนั้น a try-finallyจึงถูกใช้เพื่อให้แน่ใจว่า mutex ถูกปล่อยออกมา ( sizeCtlรีเซ็ตเป็นค่าเดิม) โดยไม่คำนึงว่าจะมีข้อยกเว้นเกิดขึ้น (เช่นหน่วยความจำไม่เพียงพอในการกำหนด Node ใหม่ - หรือมีข้อ จำกัด เฉพาะที่เกี่ยวข้องกับแผนที่) หรือไม่