ล็อคอะไรในชวา
ฉันไม่สามารถตอบคำถามนี้ได้หลังจากอ่าน <java การเขียนโปรแกรมพร้อมกัน> ซึ่งแสดงให้เห็นว่าฉันไม่เข้าใจมากพอเกี่ยวกับแนวคิดของการล็อค ดังนั้นฉันจึงมองผ่านเนื้อหาของหนังสืออีกครั้งและทันใดนั้นก็รู้สึกเหมือนฉันเปิดหน้าผาก ดูเหมือนว่าวิธีที่ดีที่สุดในการเรียนรู้คือการเรียนรู้ด้วยปัญหาและแก้ปัญหา
ใน Java มีล็อคสองประเภทหลัก: การล็อคภายในซิงโครไนซ์และแสดงล็อค java.util.concurrent.locks.lock แต่ถ้าคุณคิดอย่างระมัดระวังดูเหมือนว่าบทสรุปไม่ถูกต้อง มันควรจะเป็นชุดของล็อคที่ดำเนินการโดยล็อคในตัว Java และพร้อมกัน
ทำไมสิ่งนี้ถึงพูดเพราะใน Java ทุกอย่างเป็นวัตถุและ Java มีล็อคที่สร้างขึ้นในแต่ละวัตถุซึ่งสามารถเรียกได้ว่าล็อควัตถุ/ล็อคภายใน การดำเนินการล็อคที่เกี่ยวข้องเสร็จสมบูรณ์ผ่านการซิงโครไนซ์
เนื่องจากข้อบกพร่องในการใช้งานของการซิงโครไนซ์และความซับซ้อนของสถานการณ์พร้อมกันมีคนพัฒนาล็อคที่ชัดเจนและล็อคเหล่านี้มาจาก java.util.concurrent.locks.locks แน่นอนว่ามันถูกสร้างขึ้นใน JDK1.5 และรุ่นต่อมา
ซิงโครไนซ์
ก่อนอื่นมาดูการซิงโครไนซ์ที่ใช้บ่อยขึ้น มันยังใช้ในการทำงานประจำวันของฉัน ซิงโครไนซ์ใช้เพื่อให้กลไกการล็อคสำหรับบล็อกรหัสที่แน่นอน มันจะมีล็อคในวัตถุ Java โดยปริยาย ล็อคนี้เรียกว่าล็อคที่แท้จริงหรือตรวจสอบ เธรดจะได้รับล็อคนี้โดยอัตโนมัติก่อนที่จะป้อนบล็อกที่ได้รับการป้องกันโดยซิงโครไนซ์จนกว่าการล็อคจะถูกปล่อยออกมาโดยอัตโนมัติหลังจากรหัสเสร็จสมบูรณ์ (หรืออาจเป็นข้อยกเว้น) ล็อคในตัวนั้นไม่เหมือนกัน ล็อคสามารถถือได้เพียงหนึ่งเธรดในเวลาเดียวกันซึ่งจะนำไปสู่หลายเธรดและเธรดที่อยู่ด้านหลังล็อคจะถูกบล็อกหลังจากถูกจัดขึ้น สิ่งนี้ช่วยให้ความปลอดภัยของเธรดของรหัสเพื่อให้แน่ใจว่าเป็นอะตอม
เข้ามาอีกครั้ง
เนื่องจากล็อคในตัว Java นั้นไม่เกิดร่วมกันและเธรดที่ตามมาจะทำให้เกิดการอุดตันจะเกิดอะไรขึ้นถ้าเธรดถือล็อคเข้าสู่อีกครั้งเมื่อพยายามรับล็อค? ตัวอย่างเช่นหนึ่งในสถานการณ์ต่อไปนี้:
Baseclass ระดับสาธารณะ {โมฆะที่ซิงโครไนซ์สาธารณะ Do () {system.out.println ("เป็นฐาน"); }} ระดับสาธารณะ sonclass ขยาย baseclass {โมฆะที่ซิงโครไนซ์สาธารณะ Do () {system.out.println ("เป็นลูกชาย"); super.do (); }} sonclass son = new sonclass (); son.do ();ในเวลานี้วิธีการ DO ของคลาสที่ได้รับจะถือล็อคไว้ก่อนแล้วเข้าล็อคอีกครั้งและค้างไว้เมื่อโทร super.do () หากล็อคเป็นเอกสิทธิ์เฉพาะบุคคลควรมีการหยุดชะงักในเวลานี้
แต่ผลลัพธ์ไม่ได้เป็นเช่นนั้นเนื่องจากการล็อคภายในมีลักษณะของ reentrant นั่นคือล็อคใช้กลไก reentrant การจัดการการนับอ้างอิง เมื่อเธรด 1 ถือล็อคของวัตถุการอ้างอิงถึงล็อค A จะคำนวณโดยการเพิ่ม 1 จากนั้นเมื่อเธรด 1 ได้รับล็อค A อีกครั้งเธรด 1 ยังคงล็อค A แล้วการคำนวณจะเพิ่ม 1 แน่นอนทุกครั้งที่คุณออกจากบล็อกการซิงโครไนซ์มันจะลดลง 1 จนกระทั่งเป็น 0
คุณสมบัติบางอย่างของการซิงโครไนซ์
วิธีแก้ไขรหัส
วิธีการปรับเปลี่ยน
Baseclass ระดับสาธารณะ {โมฆะที่ซิงโครไนซ์สาธารณะ Do () {system.out.println ("เป็นฐาน"); -ซึ่งหมายถึงการล็อควิธีการโดยตรงและคุณต้องได้รับการล็อคเมื่อป้อนบล็อกวิธีนี้
แก้ไขบล็อกรหัส
Baseclass คลาสสาธารณะ {วัตถุสแตติกส่วนตัวล็อค = ใหม่วัตถุ (); โมฆะสาธารณะ DO () {ซิงโครไนซ์ (ล็อค) {System.out.println ("เป็นฐาน"); -ที่นี่ช่วงของการล็อคจะลดลงเป็นบางบล็อกโค้ดในวิธีการซึ่งช่วยเพิ่มความยืดหยุ่นของการล็อค ท้ายที่สุดการควบคุมความละเอียดของล็อคก็เป็นปัญหาสำคัญสำหรับการล็อค
ประเภทของล็อควัตถุ
ฉันมักจะเห็นว่าบางรหัสใช้การซิงโครไนซ์ในคำศัพท์พิเศษและดูรหัสต่อไปนี้:
Baseclass คลาสสาธารณะ {วัตถุสแตติกส่วนตัวล็อค = ใหม่วัตถุ (); โมฆะสาธารณะ DO () {ซิงโครไนซ์ (ล็อค) {}} โมฆะที่ซิงโครไนซ์สาธารณะเป็นโมฆะ dovoid () {} โมฆะโมฆะแบบสแตติกสาธารณะแบบซิงโครไนซ์สาธารณะ () {} โมฆะสาธารณะคงที่ DostaticVoid ()มีสี่สถานการณ์ที่นี่: การแก้ไขบล็อกรหัสแก้ไขวิธีการแก้ไขวิธีการคงที่และแก้ไขวัตถุคลาสของ baseclass แล้วสถานการณ์เหล่านี้แตกต่างกันอย่างไร?
แก้ไขบล็อกรหัส
ในกรณีนี้เราสร้างล็อควัตถุโดยใช้การซิงโครไนซ์ (ล็อค) ในรหัสซึ่งหมายถึงการใช้ล็อคในตัวของวัตถุ ในกรณีนี้การควบคุมล็อคจะถูกส่งไปยังวัตถุ แน่นอนว่ามีอีกวิธีหนึ่งในการทำเช่นนี้:
โมฆะสาธารณะ DO () {ซิงโครไนซ์ (นี่) {System.out.println ("เป็นฐาน"); -การใช้สิ่งนี้หมายถึงการล็อคของวัตถุปัจจุบัน กุญแจสำคัญในการล็อคในตัวยังถูกกล่าวถึงที่นี่ ฉันให้ล็อคเพื่อปกป้องรหัสนี้ ไม่ว่าเธรดใดจะมาถึงมันจะเผชิญกับล็อคเดียวกัน
วิธีการแก้ไขวัตถุ
สถานการณ์กับการปรับเปลี่ยนโดยตรงนี้คืออะไร? ในความเป็นจริงมันคล้ายกับการแก้ไขบล็อกโค้ดยกเว้นว่านี่คือล็อคของวัตถุปัจจุบันโดยค่าเริ่มต้น ด้วยวิธีนี้มันค่อนข้างง่ายและชัดเจนในการเขียนโค้ด ดังที่ได้กล่าวไว้ก่อนหน้านี้ความแตกต่างระหว่างการปรับเปลี่ยนบล็อกโค้ดส่วนใหญ่เป็นความแตกต่างระหว่างการควบคุมความละเอียด
ปรับเปลี่ยนวิธีการคงที่
มีอะไรที่แตกต่างเกี่ยวกับวิธีการคงที่หรือไม่? มันแตกต่างกันจริงๆ ล็อคที่ได้รับในเวลานี้ไม่ได้เป็นอีกต่อไปและคลาสที่ชี้ไปที่วัตถุนี้คือการล็อคคลาส เนื่องจากข้อมูลชั้นเรียนใน Java จะถูกโหลดลงในพื้นที่ค่าคงที่ของวิธีการทั่วโลกจึงไม่ซ้ำกัน นี่เป็นล็อคทั่วโลก
วัตถุคลาสของคลาสที่ได้รับการแก้ไข
สถานการณ์นี้ค่อนข้างคล้ายกับเมื่อปรับเปลี่ยนวิธีการคงที่ แต่ก็ยังเป็นเหตุผลเดียวกัน วิธีนี้สามารถให้ความละเอียดควบคุมที่ยืดหยุ่นมากขึ้น
สรุป
ผ่านการวิเคราะห์และทำความเข้าใจกับสถานการณ์เหล่านี้เราจะเห็นได้ว่าแนวคิดหลักหลักของการล็อคในตัวคือการจัดเตรียมรหัสชิ้นส่วนที่มีล็อคที่สามารถใช้สำหรับเอกสิทธิ์เฉพาะบุคคลร่วมกันและเล่นฟังก์ชั่นคล้ายกับสวิตช์
Java ยังมีการใช้งานบางอย่างสำหรับการล็อคในตัว คุณสมบัติหลักคือ Java เป็นวัตถุทั้งหมดและแต่ละวัตถุมีล็อคดังนั้นคุณสามารถเลือกล็อคที่จะใช้ตามสถานการณ์
java.util.concurrent.locks.lock
ฉันดูที่ซิงโครไนซ์ก่อนหน้านี้ ในกรณีส่วนใหญ่มันเกือบจะเพียงพอ อย่างไรก็ตามระบบมีความซับซ้อนมากขึ้นเรื่อย ๆ ในการเขียนโปรแกรมพร้อมกันดังนั้นจึงมีหลายสถานการณ์ที่การประมวลผลแบบซิงโครไนซ์นั้นยากขึ้น หรือตามที่ระบุไว้ใน <การเขียนโปรแกรมพร้อมกันของ <java> การล็อคในการเกิดขึ้นพร้อมกันเป็นส่วนประกอบของล็อคภายในซึ่งให้คุณสมบัติขั้นสูงมากขึ้น
การวิเคราะห์อย่างง่าย ๆ ของ java.util.concurrent.locks.lock
อินเทอร์เฟซนี้เป็นบทสรุปการทำงานหลักของการล็อคและทำให้ล็อคที่ได้จากล็อคมีลักษณะพื้นฐานเหล่านี้: ไม่มีเงื่อนไข, เป็นวงจร, หมดเวลา, ไม่สามารถขัดจังหวะได้ ยิ่งไปกว่านั้นการล็อคและการปลดล็อคจะดำเนินการอย่างชัดเจน นี่คือรหัส:
ล็อคอินเตอร์เฟสสาธารณะ {void lock (); เป็นโมฆะล็อคอย่างต่อเนื่อง () พ่น InterruptedException; บูลีน trylock (); บูลีน trylock (นาน, หน่วยเวลา) พ่น InterruptedException; โมฆะปลดล็อค (); เงื่อนไข newCondition ();} reentrantlock
Reentrantlock เป็นล็อคอีกครั้งแม้แต่ชื่อก็ชัดเจน Reentrantlock ให้ความหมายที่คล้ายกันกับการซิงโครไนซ์ แต่ reentrantlock จะต้องเรียกอย่างชัดเจนเช่น:
Baseclass คลาสสาธารณะ {ล็อคส่วนตัว = ใหม่ reentrantlock (); โมฆะสาธารณะ DO () {lock.lock (); ลอง {// .. } ในที่สุด {lock.unlock (); -วิธีนี้ค่อนข้างชัดเจนสำหรับการอ่านรหัส แต่มีปัญหานั่นคือถ้าคุณลืมเพิ่มลองในที่สุดหรือลืมที่จะเขียน lock.unlock () มันจะทำให้ล็อคไม่ได้รับการปล่อยตัวซึ่งอาจนำไปสู่การหยุดชะงักบางอย่าง ไม่มีความเสี่ยงที่จะซิงโครไนซ์
ทริลล็อก
Reentrantlock ใช้อินเทอร์เฟซล็อคดังนั้นจึงมีคุณสมบัติตามธรรมชาติรวมถึง Trylock Trylock คือพยายามที่จะได้รับการล็อค หากล็อคถูกครอบครองโดยเธรดอื่นมันจะส่งคืนเท็จทันที หากไม่เป็นเช่นนั้นควรถูกครอบครองและกลับมาเป็นจริงซึ่งหมายความว่าได้รับการล็อค
อีกวิธี Trylock มีพารามิเตอร์ ฟังก์ชั่นของวิธีนี้คือการระบุเวลาซึ่งหมายความว่าคุณพยายามที่จะได้รับการล็อคในช่วงเวลานี้และยอมแพ้หากไม่ได้รับเวลา
เนื่องจาก Trylock ไม่ได้บล็อกและรอล็อคเสมอมันสามารถหลีกเลี่ยงการเกิดหยุดชะงักได้มากขึ้น
อย่างต่อเนื่อง
ล็อคตอบสนองต่อการขัดจังหวะเมื่อเธรดได้รับการล็อค หากตรวจพบการขัดจังหวะข้อยกเว้นการขัดจังหวะจะถูกโยนโดยรหัสชั้นบน ในกรณีนี้กลไกการออกมีไว้สำหรับล็อคกลมกลม เพื่อให้เข้าใจการดำเนินการล็อคที่ขัดจังหวะได้ดีขึ้นการสาธิตถูกเขียนขึ้นเพื่อทำความเข้าใจ
แพ็คเกจ com.test; นำเข้า java.util.date; นำเข้า java.util.concurrent.locks.reentrantlock; การทดสอบระดับสาธารณะ testlockincintably {คงที่ reentrantlock lock = ใหม่ reentrantlock (); โมฆะคงที่สาธารณะหลัก (สตริง [] args) {เธรดเธรด 1 = เธรดใหม่ (ใหม่ runnable () {@Override โมฆะสาธารณะเรียกใช้ () {ลอง {doprint ("เธรด 1 รับล็อค"); do123 (); doprint ("ด้าย 1 end."); เธรดเธรด 2 = เธรดใหม่ (ใหม่ runnable () {@Override โมฆะสาธารณะเรียกใช้ () {ลอง {doprint ("เธรด 2 รับล็อค"); do123 (); doprint ("เธรด 2 ปลาย.");} catch (interruptedexception e) {doprint Thread1.setName ("Thread1"); thread2.setName ("thread2"); Thread1.start (); ลอง {thread.sleep (100); // รอสักครู่เพื่อให้ด้าย 1 ดำเนินการด้านหน้าของ Thread2} catch (interruptedException E) {E.printStackTrace (); } thread2.start (); } โมฆะคงที่ส่วนตัว do123 () พ่น InterruptedException {lock.lockinctiverunctibly (); doprint (thread.currentthread (). getName () + "ถูกล็อค"); ลอง {doprint (thread.currentthread (). getName () + "dosoming1 .... "); thread.sleep (5000); // ค่าใช้จ่ายไม่กี่วินาทีเพื่ออำนวยความสะดวกในการดูลำดับของเธรด doprint (thread.currentthread (). getName () + "Dosoming2 .... "); doprint (thread.currentthread (). getName () + "เสร็จสิ้น"); } ในที่สุด {lock.unlock (); }} doprint โมฆะคงที่ส่วนตัว (ข้อความสตริง) {system.out.println ((วันที่ใหม่ ()). tolocalestring () + ":" + ข้อความ); -มีสองเธรดในรหัสด้านบน Thread1 เริ่มต้นเร็วกว่า Thread2 เพื่อที่จะเห็นกระบวนการล็อครหัสล็อคจะถูกทำให้นอนหลับเป็นเวลา 5 วินาทีเพื่อให้คุณสามารถรู้สึกถึงกระบวนการของเธรดที่หนึ่งและที่สองที่เข้าสู่กระบวนการล็อค ผลลัพธ์สุดท้ายของรหัสข้างต้นมีดังนี้:
2016-9-28 15:12:56: เธรด 1 รับล็อค
2016-9-28 15:12:56: Thread1 ถูกล็อค
2016-9-28 15:12:56: Thread1 Dosoming1 ....
2016-9-28 15:12:56: เธรด 2 รับล็อค
2016-9-28 15:13:01: Thread1 Dosoming2 ....
2016-9-28 15:13:01: Thread1 เสร็จสิ้นแล้ว
2016-9-28 15:13:01: Thread1 ถูกขนถ่าย
2016-9-28 15:13:01: Thread2 ถูกล็อค
2016-9-28 15:13:01: Thread2 Dosoming1 ....
2016-9-28 15:13:01: เธรด 1 End
2016-9-28 15:13:06: Thread2 Dosoming2 ....
2016-9-28 15:13:06: Thread2 เสร็จสิ้นแล้ว
2016-9-28 15:13:06: การขนถ่าย Thread2
2016-9-28 15:13:06: เธรด 2 End
จะเห็นได้ว่า Thread1 ได้รับการล็อคก่อนและ Thread2 จะได้รับการล็อคในภายหลัง แต่ Thread1 ได้ครอบครองมันในเวลานี้ดังนั้น Thread2 จะไม่ได้รับการล็อคจนกว่า Thread1 จะปล่อยล็อค
** รหัสนี้แสดงให้เห็นว่าเธรดที่อยู่เบื้องหลังการล็อคอย่างต่อเนื่องเพื่อให้ได้ล็อคจำเป็นต้องรอให้ล็อคก่อนหน้านี้ถูกปล่อยออกมาก่อนที่จะได้รับการล็อค ** แต่ยังไม่มีคุณสมบัติขัดจังหวะดังนั้นบางรหัสจะถูกเพิ่มเข้าไปในนี้:
thread2.start (); ลอง {thread.sleep (1,000); } catch (interruptedException e) {e.printStackTrace ();} // interrupt thread2 ใน 1 วินาที thread2.interrupt ();หลังจากเริ่มต้น Thread2 แล้วให้ใช้วิธีการขัดจังหวะของ Thread2 ตกลงเรียกใช้รหัสก่อนและดูผลลัพธ์:
2016-9-28 15:16:46: เธรด 1 รับล็อค
2016-9-28 15:16:46: Thread1 ถูกล็อค
2016-9-28 15:16:46: Thread1 Dosoming1 ....
2016-9-28 15:16:46: เธรด 2 รับล็อค
2016-9-28 15:16:47: เธรด 2 ถูกขัดจังหวะ <-ตอบสนองโดยตรงต่อการขัดจังหวะเธรด
2016-9-28 15:16:51: Thread1 Dosoming2 ....
2016-9-28 15:16:51: Thread1 เสร็จสิ้นแล้ว
2016-9-28 15:16:51: Thread1 ถูกขนถ่าย
2016-9-28 15:16:51: เธรด 1 End
เมื่อเทียบกับรหัสก่อนหน้านี้อาจพบได้ว่า Thread2 กำลังรอให้ Thread1 ปล่อยล็อค แต่เธรด 2 นั้นขัดจังหวะและรหัสที่อยู่เบื้องหลัง Thread2 จะไม่ถูกดำเนินการต่อไป
ReadWriteLock
ตามชื่อที่แนะนำมันเป็นล็อคอ่าน-เขียน สถานการณ์แอปพลิเคชันการอ่านแบบอ่าน-เขียนแบบนี้สามารถเข้าใจได้ด้วยวิธีนี้ ตัวอย่างเช่นคลื่นของข้อมูลส่วนใหญ่มีไว้สำหรับการอ่านและมีเพียงการดำเนินการเขียนค่อนข้างน้อย หากใช้การล็อค mutex มันจะนำไปสู่การแข่งขันล็อคระหว่างเธรด หากทุกคนสามารถอ่านได้เมื่ออ่านให้ล็อคทรัพยากรเมื่อต้องเขียน การเปลี่ยนแปลงดังกล่าวช่วยแก้ปัญหานี้ได้ดีช่วยให้การดำเนินการอ่านปรับปรุงประสิทธิภาพการอ่านโดยไม่ส่งผลกระทบต่อการดำเนินการเขียน
ผู้อ่านหลายคนสามารถเข้าถึงทรัพยากรได้หรือเข้าถึงโดยนักเขียนคนหนึ่งและไม่สามารถดำเนินการพร้อมกันได้
นี่คืออินเทอร์เฟซนามธรรมสำหรับการอ่านและเขียนล็อคการกำหนดล็อคการอ่านและล็อคการเขียน
อินเทอร์เฟซสาธารณะ ReadWriteLock { /*** ส่งคืนล็อคที่ใช้สำหรับการอ่าน * * @return ล็อคที่ใช้สำหรับการอ่าน */ ล็อค readlock (); /*** ส่งคืนล็อคที่ใช้สำหรับการเขียน * * @return ล็อคที่ใช้สำหรับเขียน */ ล็อค writeLock ();}มีการใช้งาน ReentRantReadWriteLock ใน JDK ซึ่งเป็นล็อคอ่านอ่านซ้ำอีกครั้ง ReentRantReadWriteLock สามารถสร้างเป็นสองประเภท: ยุติธรรมหรือไม่ยุติธรรม หากไม่ได้ระบุไว้อย่างชัดเจนในระหว่างการก่อสร้างจะมีการล็อคที่ไม่ใช่ค่าธรรมเนียมโดยค่าเริ่มต้น ในโหมดล็อคที่ไม่ใช่ Fair ลำดับของการเข้าถึงเธรดไม่แน่นอนนั่นคือมันสามารถแบ่งออกเป็น; มันสามารถลดระดับจากนักเขียนเป็นผู้อ่านได้ แต่ผู้อ่านไม่สามารถอัพเกรดเป็นนักเขียนได้
หากเป็นโหมดล็อคที่ยุติธรรมตัวเลือกจะถูกส่งไปยังเธรดด้วยเวลารอคอยที่ยาวที่สุด หากเธรดอ่านจะได้รับล็อคและเธรดการเขียนคำขอล็อคการเขียนการล็อคการอ่านจะไม่ได้รับอีกต่อไปจนกว่าการดำเนินการเขียนจะเสร็จสมบูรณ์
การวิเคราะห์รหัสอย่างง่ายจริง ๆ แล้วยังคงรักษาซิงค์ล็อคใน ReentRantReadWriteLock แต่ดูเหมือนว่าความหมายเหมือนล็อคการอ่านและล็อคการเขียน ลองดูที่ตัวสร้าง:
สาธารณะ reentRantReadWriteLock (Boolean Fair) {sync = fair? ใหม่ fairsync (): nonfairsync ใหม่ (); readerLock = ใหม่ readLock (นี่); writerlock = new writeLock (this);} // ตัวสร้างของ Read Lock Protected Readlock (ReentRantReadWriteLock Lock) {sync = lock.sync;} // ตัวสร้างการล็อค WriteLockคุณจะเห็นว่าวัตถุซิงค์ล็อคของ ReentRantReadWriteLock นั้นอ้างอิงจริงเมื่อสร้างขึ้น และคลาสการซิงค์นี้เป็นคลาสภายในของ ReentRantReadWriteLock ในระยะสั้นการอ่าน/เขียนล็อคทั้งหมดจะเสร็จสิ้นผ่านการซิงค์ มันร่วมมือกับความสัมพันธ์ระหว่างทั้งสองได้อย่างไร?
// วิธีการล็อคสำหรับการอ่านล็อคโมฆะสาธารณะล็อค () {sync.acquireshared (1);} // วิธีการล็อคสำหรับการเขียนล็อคโมฆะล็อคสาธารณะล็อค () {sync.acquire (1);};ความแตกต่างที่สำคัญคือการล็อคการอ่านจะได้รับการล็อคที่ใช้ร่วมกันในขณะที่ล็อคการเขียนได้รับล็อคพิเศษ มีจุดที่นี่ที่สามารถกล่าวถึงได้นั่นคือเพื่อให้แน่ใจว่า reentrantreadwriteLock ทั้งล็อคที่ใช้ร่วมกันและล็อคพิเศษจะต้องสนับสนุนการนับจำนวนและการเข้าร่วม Reentrantlock ถูกเก็บไว้โดยใช้สถานะและสถานะสามารถเก็บค่าการรูปร่างเดียวเท่านั้น เพื่อให้เข้ากันได้กับปัญหาของการล็อคสองตัวจะถูกแบ่งออกเป็นจำนวนเธรดที่ถือล็อคที่ใช้ร่วมกันหรือจำนวนเธรดที่ถือล็อคแบบพิเศษหรือจำนวนการเข้ากลับตามลำดับ
อื่น
ฉันเขียนบทความขนาดใหญ่ที่ฉันรู้สึกว่ามันใช้เวลานานเกินไปในการเขียนและมีล็อคที่มีประโยชน์มากกว่านี้:
นับถอยหลัง
มันคือการตั้งค่าเคาน์เตอร์ที่จัดขึ้นพร้อมกัน เมื่อผู้โทรเรียกใช้วิธีการรอคอยของ Countdownlatch มันจะบล็อกหากตัวนับปัจจุบันไม่ใช่ 0 การโทรวิธีการวางจำหน่ายของ Countdownlatch สามารถลดการนับได้จนกว่าผู้โทรที่โทรรอจะปลดบล็อก
เซมาฟีน
Semaphore เป็นรูปแบบของการอนุญาตและใบอนุญาตเช่นการตั้งค่าใบอนุญาต 100 ใบเพื่อให้ 100 เธรดสามารถถือล็อคได้ในเวลาเดียวกันและหากจำนวนเงินนี้เกินกว่าจะกลับไปสู่ความล้มเหลว
ขอบคุณสำหรับการอ่านบทความนี้ฉันหวังว่ามันจะช่วยคุณได้ ขอบคุณสำหรับการสนับสนุนเว็บไซต์นี้!