ก่อน Java 5.0 มีเพียงการซิงโครไนซ์ (ล็อคในตัว) และระเหยได้ หลังจาก Java 5.0 มีการแนะนำการล็อคการแสดงผล ReentrantLock
ภาพรวม ReentrantLock
ReentrantLock เป็นการล็อคแบบกลับเข้าใหม่ โดยต้องมีการล็อคและปลดล็อคอย่างชัดเจนทุกครั้งที่ใช้งาน และมีคุณสมบัติขั้นสูงเพิ่มเติม เช่น การล็อคที่ยุติธรรม การล็อคแบบกำหนดเวลา การล็อคแบบมีเงื่อนไข และการล็อคแบบโพลล์ สามารถขัดจังหวะได้ การล็อค สามารถหลีกเลี่ยงปัญหาการหยุดชะงักของ ReentrantLock ได้อย่างมีประสิทธิภาพ
ล็อคอินเตอร์เฟซ:
คัดลอกรหัสรหัสดังต่อไปนี้:
ล็อคอินเทอร์เฟซสาธารณะ {
//บล็อกจนกว่าจะได้รับการล็อคหรือถูกขัดจังหวะ
ล็อคเป็นโมฆะ();
//บล็อกจนกว่าจะได้รับการล็อคหรือมีข้อยกเว้นเกิดขึ้นเมื่อขัดจังหวะ
โมฆะล็อคInterruptually () พ่น InterruptedException;
//รับเฉพาะเมื่อมีการล็อคเท่านั้น ไม่อย่างนั้นจะส่งคืนโดยตรง
tryLock บูลีน ();
//รับการล็อคเฉพาะในกรณีที่สามารถใช้ได้ภายในเวลาที่กำหนด ไม่เช่นนั้นให้ส่งคืนโดยตรงและส่งข้อยกเว้นเมื่อถูกขัดจังหวะ
บูลีน tryLock (หน่วย TimeUnit เป็นเวลานาน) พ่น InterruptedException;
ปลดล็อคเป็นโมฆะ();
//คืนเงื่อนไขที่ผูกไว้กับล็อคนี้
เงื่อนไข เงื่อนไขใหม่();
-
ล็อคการใช้งาน
คัดลอกรหัสรหัสดังต่อไปนี้:
ล็อค ล็อค = ReentrantLock ใหม่ ();
ล็อค.ล็อค();
พยายาม{
// อัพเดตสถานะวัตถุ
}ในที่สุด{
//หมายเหตุ ที่นี่ ท้ายที่สุดจะต้องมีบล็อกโค้ดเพื่อปลดล็อก
//มิฉะนั้น อาจเกิดปัญหาการหยุดชะงักและปัญหากิจกรรมอื่นๆ ได้ง่าย
ล็อค.ปลดล็อค();
-
คุณสมบัติ ReentrantLock
ล็อคการลงคะแนนและการล็อคแบบหมดเวลา
การร้องขอการล็อกแบบสำรวจได้และตามเวลาจะถูกนำไปใช้ผ่านเมธอด tryLock() ซึ่งแตกต่างจากการรับการล็อกแบบไม่มีเงื่อนไข ReentrantLock อาจมีกลไกที่ยืดหยุ่นในการทนต่อการหยุดชะงัก หลายๆ กรณีเกิดจากการล็อกตามลำดับ และเธรดต่างๆ กำลังพยายามรับ ล็อค มันจะบล็อกเมื่อล็อคและไม่ปล่อยล็อคที่ถืออยู่จนทำให้เกิดการหยุดชะงักในที่สุด เมื่อเมธอด tryLock() พยายามรับการล็อค ถ้าการล็อคถูกยึดไว้แล้วโดยเธรดอื่น มันจะกลับมาทันทีตามวิธีการตั้งค่า แทนที่จะบล็อกและรอ ในเวลาเดียวกัน มันจะปล่อยการล็อคที่ถือไว้หลังจากนั้น การส่งคืน คุณสามารถส่งคืนได้ตามการส่งคืน ด้วยเหตุนี้ จึงดำเนินการลองใหม่หรือยกเลิกเพื่อหลีกเลี่ยงการหยุดชะงัก
ความเป็นธรรม
ตัวสร้าง ReentrantLock มีสองตัวเลือก: การล็อคที่ยุติธรรมและการล็อคที่ไม่ยุติธรรม (ค่าเริ่มต้น) สิ่งที่เรียกว่าการล็อคที่ยุติธรรม เธรดจะได้รับการล็อคตามลำดับที่ร้องขอ และไม่อนุญาตให้มีการกระโดดคิว แต่สำหรับการล็อคที่ไม่ยุติธรรม เธรดจะได้รับอนุญาตให้ทำการกระโดดได้: เมื่อเธรดร้องขอเพื่อรับการล็อค หากมีการล็อค จากนั้นเธรดนี้จะข้ามเธรดที่รออยู่ในคิวและรับการล็อก โดยทั่วไปเราต้องการให้ล็อคทั้งหมดไม่ยุติธรรม เนื่องจากเมื่อทำการล็อค ความเที่ยงตรงจะลดประสิทธิภาพลงอย่างมาก เนื่องจากโอเวอร์เฮดของการระงับเกลียวและการกู้คืนเกลียว พิจารณาสถานการณ์: เธรด A ล็อคไว้ เธรด B ร้องขอการล็อค ดังนั้นเธรด B จึงถูกระงับ เมื่อเธรด A ปลดล็อค เธรด B จะถูกปลุกให้ทำงาน ดังนั้นจึงพยายามรับการล็อคอีกครั้ง ในเวลาเดียวกัน C นอกจากนี้ ร้องขอให้รับการล็อคนี้ ดังนั้นเธรด C มีแนวโน้มที่จะได้รับ ใช้ และปลดล็อคนี้ก่อนที่เธรด B จะถูกปลุกอย่างเต็มที่ นี่เป็นสถานการณ์ที่ได้ประโยชน์ทั้งสองฝ่าย ช่วงเวลาที่ B ได้รับการล็อค (B สามารถรับการล็อคได้หลังจากที่มันเริ่มทำงานเท่านั้น) จะไม่ล่าช้า C ได้รับการล็อคเร็วขึ้นและปริมาณงานก็ได้รับการปรับปรุงด้วย ในกรณีส่วนใหญ่ ประสิทธิภาพของแฟร์ล็อคจะสูงกว่าประสิทธิภาพของแฟร์ล็อค
การดำเนินการรับล็อคสามารถถูกขัดจังหวะได้
วิธีการ lockInterruptually รับการล็อคในขณะที่ยังคงตอบสนองต่อการขัดจังหวะ ดังนั้นจึงไม่จำเป็นต้องสร้างการดำเนินการบล็อกอย่างต่อเนื่องประเภทอื่น
ReadWriteLockReadWriteLock
ReentrantLock เป็นการล็อค mutex มาตรฐาน มีเพียงเธรดเดียวเท่านั้นที่สามารถล็อคได้ในแต่ละครั้ง การล็อกการอ่าน-เขียนแตกต่างกัน โดยจะแสดงอ็อบเจ็กต์ Lock สองตัว ซึ่งอันหนึ่งใช้สำหรับการดำเนินการอ่านและอีกอันสำหรับการดำเนินการเขียน
คัดลอกรหัสรหัสดังต่อไปนี้:
อินเทอร์เฟซสาธารณะ ReadWriteLock {
-
* คืนล็อคที่ใช้ในการอ่าน
-
* @คืนล็อคที่ใช้อ่าน
-
ล็อค readLock();
-
* คืนตัวล็อคที่ใช้ในการเขียน
-
* @คืนล็อคที่ใช้เขียน
-
ล็อค writeLock();
-
การใช้งานทางเลือก:
1. ลำดับความสำคัญในการเผยแพร่
2. อ่านการข้ามเธรดในบรรทัด
3. การกลับเข้ามาใหม่
4.ดาวน์เกรด
5.อัปเกรด
ReentrantReadWriteLock ใช้อินเทอร์เฟซ ReadWriteLock และตัวสร้างมีวิธีการสร้างสองวิธี: การล็อคที่ยุติธรรมและการล็อคที่ไม่ยุติธรรม การล็อกการอ่าน-เขียนเหมาะสำหรับสถานการณ์ที่มีการอ่านมากขึ้นและการเขียนน้อยลง และสามารถบรรลุการทำงานพร้อมกันได้ดีขึ้น
รหัสการคัดลอกตัวอย่างจะเป็นดังนี้:
ReadWriteMap คลาสสาธารณะ <K, V> {
แผนที่ส่วนตัว <K, V> แผนที่;
ล็อค ReadWriteLock สุดท้ายส่วนตัว = ReentrantReadWriteLock ใหม่ ();
ล็อคสุดท้ายส่วนตัว readLock = lock.readLock();
ล็อคสุดท้ายส่วนตัว writeLock = lock.writeLock();
สาธารณะ ReadWriteMap (แผนที่ <K, V>) {
this.map = แผนที่;
-
สาธารณะ V รับ (คีย์ K) {
readLock.ล็อค();
พยายาม {
กลับ map.get (คีย์);
} ในที่สุด {
readLock.unlock();
-
-
โมฆะสาธารณะใส่ (คีย์ K, ค่า V) {
writeLock.ล็อค();
พยายาม {
map.put (คีย์, ค่า);
} ในที่สุด {
writeLock.ปลดล็อค();
-
-
-