คำหลักที่ซิงโครไนซ์
ซิงโครไนซ์เราเรียกล็อคส่วนใหญ่จะใช้เพื่อล็อควิธีและบล็อกรหัส เมื่อวิธีการหรือบล็อกรหัสถูกซิงโครไนซ์ส่วนใหญ่หนึ่งเธรดจะดำเนินการรหัสในเวลาเดียวกัน เมื่อหลายเธรดเข้าถึงวิธีการล็อค/บล็อกโค้ดของวัตถุเดียวกันมีเพียงเธรดเดียวเท่านั้นที่จะดำเนินการในเวลาเดียวกันและเธรดที่เหลือจะต้องรอให้เธรดปัจจุบันเรียกใช้เซ็กเมนต์โค้ดก่อนที่จะดำเนินการ อย่างไรก็ตามเธรดที่เหลือสามารถเข้าถึงบล็อกรหัสที่ไม่ล็อคในวัตถุ
ซิงโครไนซ์ส่วนใหญ่มีสองวิธี: วิธีการซิงโครไนซ์และบล็อกซิงโครไนซ์
วิธีการซิงโครไนซ์
ประกาศวิธีการซิงโครไนซ์โดยการเพิ่มคำหลักที่ซิงโครไนซ์ลงในการประกาศวิธีการ ชอบ:
เป็นโมฆะที่ซิงโครไนซ์สาธารณะ getResult ();
วิธีการซิงโครไนซ์ควบคุมการเข้าถึงตัวแปรสมาชิกในชั้นเรียน มันหลีกเลี่ยงการควบคุมการเข้าถึงตัวแปรสมาชิกในชั้นเรียนได้อย่างไร? เรารู้ว่าวิธีการใช้คำหลักที่ซิงโครไนซ์เพื่อระบุว่าวิธีการล็อค เมื่อเธรดใด ๆ เข้าถึงวิธีการแก้ไขจำเป็นต้องพิจารณาว่าเธรดอื่น ๆ นั้นเป็น "เอกสิทธิ์" หรือไม่ แต่ละอินสแตนซ์ของคลาสสอดคล้องกับการล็อค แต่ละวิธีที่ซิงโครไนซ์จะต้องเรียกล็อคของอินสแตนซ์คลาสของวิธีก่อนที่จะสามารถดำเนินการได้ มิฉะนั้นเธรดที่เป็นของมันถูกบล็อก เมื่อใช้วิธีการล็อคจะเป็นเอกสิทธิ์ ล็อคจะไม่ถูกปล่อยออกมาจนกว่าจะกลับมาจากวิธีการและเธรดที่ถูกบล็อกสามารถรับล็อคได้
ในความเป็นจริงวิธีที่ซิงโครไนซ์มีข้อบกพร่อง หากเราประกาศวิธีการขนาดใหญ่ที่ซิงโครไนซ์มันจะส่งผลกระทบอย่างมากต่อประสิทธิภาพ หากหลายเธรดกำลังเข้าถึงวิธีการซิงโครไนซ์แล้วเธรดเดียวเท่านั้นที่ใช้วิธีการในเวลาเดียวกันในขณะที่เธรดอื่นต้องรอ อย่างไรก็ตามหากวิธีการไม่ใช้ซิงโครไนซ์เธรดทั้งหมดสามารถดำเนินการได้ในเวลาเดียวกันลดเวลาการดำเนินการทั้งหมด ดังนั้นหากเรารู้ว่าวิธีการจะไม่ถูกดำเนินการโดยหลายเธรดหรือไม่มีปัญหาในการแบ่งปันทรัพยากรเราไม่จำเป็นต้องใช้คำหลักที่ซิงโครไนซ์ แต่ถ้าเราต้องใช้คำหลักที่ซิงโครไนซ์เราสามารถแทนที่วิธีการซิงโครไนซ์โดยบล็อกรหัสที่ซิงโครไนซ์
บล็อกซิงโครไนซ์
บล็อกรหัสที่ซิงโครไนซ์มีบทบาทเช่นเดียวกับวิธีการซิงโครไนซ์ยกเว้นว่าจะทำให้พื้นที่วิกฤตสั้นที่สุดเท่าที่จะทำได้ กล่าวอีกนัยหนึ่งมันปกป้องข้อมูลที่ใช้ร่วมกันที่จำเป็นเท่านั้นโดยปล่อยให้การดำเนินการนี้สำหรับบล็อกรหัสยาวที่เหลืออยู่ ไวยากรณ์มีดังนี้:
ซิงโครไนซ์ (วัตถุ) {// รหัสที่อนุญาตให้ควบคุมการเข้าถึง} หากเราต้องการใช้คำหลักที่ซิงโครไนซ์ในวิธีนี้เราต้องใช้การอ้างอิงวัตถุเป็นพารามิเตอร์ โดยปกติเรามักจะใช้พารามิเตอร์นี้เป็นสิ่งนี้มีความเข้าใจดังต่อไปนี้เกี่ยวกับการซิงโครไนซ์ (นี้):
1. เมื่อสองเธรดพร้อมกันเข้าถึงบล็อกรหัสที่ซิงโครไนซ์นี้ (นี้) ซิงโครไนซ์ในวัตถุวัตถุเดียวกันสามารถดำเนินการได้เพียงหนึ่งเธรดภายในหนึ่งครั้ง เธรดอื่นจะต้องรอให้เธรดปัจจุบันเรียกใช้งานบล็อกรหัสนี้ก่อนที่จะสามารถเรียกใช้งานบล็อกรหัส
2. อย่างไรก็ตามเมื่อเธรดหนึ่งเข้าถึงบล็อกรหัสซิงโครไนซ์ซิงโครไนซ์หนึ่งตัวของวัตถุของวัตถุเธรดอื่นยังสามารถเข้าถึงบล็อกรหัสซิงโครไนซ์ที่ไม่ซิงโครไนซ์ (นี่) ในวัตถุ
3. เป็นสิ่งสำคัญอย่างยิ่งที่เมื่อเธรดเข้าถึงบล็อกรหัสการซิงโครไนซ์ซิงโครไนซ์ (นี้) ของวัตถุเธรดอื่น ๆ จะถูกบล็อกจากการเข้าถึงบล็อกการซิงโครไนซ์อื่น ๆ ทั้งหมด (นี้) ในวัตถุ
4. ตัวอย่างที่สามยังใช้กับบล็อกรหัสการซิงโครไนซ์อื่น ๆ นั่นคือเมื่อเธรดเข้าถึงบล็อกรหัสซิงโครไนซ์ซิงโครไนซ์ (นี้) ของวัตถุจะได้รับการล็อควัตถุของวัตถุนี้ เป็นผลให้เธรดอื่น ๆ เข้าถึงส่วนรหัสแบบซิงโครนัสทั้งหมดของวัตถุวัตถุจะถูกบล็อกชั่วคราว
ล็อค
มีหลักการ "มาก่อนในภายหลัง" หลักการใน Java multithreading นั่นคือใครก็ตามที่คว้ากุญแจก่อนจะใช้มันก่อน เรารู้ว่าเพื่อหลีกเลี่ยงปัญหาเกี่ยวกับการแข่งขันทรัพยากร Java ใช้กลไกการซิงโครไนซ์เพื่อหลีกเลี่ยงและกลไกการซิงโครไนซ์ถูกควบคุมโดยใช้แนวคิดของการล็อค ดังนั้นการล็อคจะสะท้อนในโปรแกรม Java ได้อย่างไร? ที่นี่เราต้องหาสองแนวคิด:
ล็อคคืออะไร? ในชีวิตประจำวันมันเป็นเครื่องปิดผนึกที่เพิ่มเข้ามาในประตูกล่องลิ้นชักและวัตถุอื่น ๆ ซึ่งป้องกันไม่ให้ผู้อื่นแอบมองหรือขโมยและมีบทบาทในการป้องกัน เช่นเดียวกันในชวา ล็อคมีบทบาทในการปกป้องวัตถุ หากเธรดเฉพาะที่ใช้ทรัพยากรบางอย่างไม่ต้องการใช้เธรดอื่น ๆ แต่ต้องการใช้หรือไม่ มาพูดถึงเรื่องนี้เมื่อฉันใช้มันเสร็จ!
ในสภาพแวดล้อมที่ใช้งานโปรแกรม Java JVM จำเป็นต้องประสานข้อมูลที่ใช้ร่วมกันโดยสองประเภทของเธรด:
1. ตัวแปรอินสแตนซ์ที่บันทึกไว้ในกอง
2. ตัวแปรคลาสบันทึกในพื้นที่วิธีการ
ในเครื่องเสมือน Java แต่ละวัตถุและคลาสจะเชื่อมโยงอย่างมีเหตุผลกับจอภาพ สำหรับวัตถุจอภาพที่เกี่ยวข้องจะปกป้องตัวแปรอินสแตนซ์ของวัตถุ สำหรับชั้นเรียนตรวจสอบปกป้องตัวแปรชั้นเรียน หากวัตถุไม่มีตัวแปรอินสแตนซ์หรือคลาสไม่มีตัวแปรจอภาพที่เกี่ยวข้องจะไม่ตรวจสอบอะไรเลย
เพื่อที่จะใช้ความสามารถในการตรวจสอบพิเศษของจอภาพเครื่องเสมือน Java ได้เชื่อมโยงล็อคสำหรับแต่ละวัตถุและคลาส แสดงถึงสิทธิพิเศษที่มีเพียงเธรดเดียวเท่านั้นที่สามารถมีได้ตลอดเวลา เธรดไม่จำเป็นต้องล็อคเมื่อเข้าถึงตัวแปรอินสแตนซ์หรือตัวแปรคลาส หากเธรดได้รับล็อคมันเป็นไปไม่ได้ที่เธรดอื่น ๆ จะได้รับการล็อคเดียวกันก่อนที่จะปล่อยล็อค เธรดสามารถล็อควัตถุเดียวกันได้หลายครั้ง สำหรับแต่ละวัตถุเครื่องเสมือน Java จะรักษาตัวนับล็อคไว้ ทุกครั้งที่เธรดได้รับวัตถุตัวนับจะเพิ่มขึ้น 1 และทุกครั้งที่ปล่อยออกมาตัวนับจะลดลง 1 เมื่อค่าตัวนับเป็น 0 การล็อคจะถูกปล่อยออกมาอย่างสมบูรณ์
โปรแกรมเมอร์ Java ไม่จำเป็นต้องเพิ่มล็อคด้วยตัวเองล็อควัตถุจะถูกใช้ภายในโดยเครื่องเสมือน Java ในโปรแกรม Java คุณจะต้องใช้บล็อกที่ซิงโครไนซ์หรือวิธีการซิงโครไนซ์เพื่อทำเครื่องหมายพื้นที่ตรวจสอบ เมื่อใดก็ตามที่คุณเข้าสู่พื้นที่การตรวจสอบเครื่องเสมือน Java จะล็อควัตถุหรือคลาสโดยอัตโนมัติ
ล็อคง่ายๆ
เมื่อใช้ซิงโครไนซ์เราใช้ล็อคเช่นนี้:
Public Class ThreadTest {Public Void Test () {ซิงโครไนซ์ (นี่) {// ทำอะไร}}}ซิงโครไนซ์ทำให้มั่นใจได้ว่ามีเพียงเธรดเดียวเท่านั้นที่กำลังดำเนินการ Dosomething ในเวลาเดียวกัน นี่คือการใช้ล็อคแทนการซิงโครไนซ์:
ชั้นเรียนสาธารณะ Threadtest {Lock Lock = new Lock (); การทดสอบโมฆะสาธารณะ () {lock.lock (); // ทำอะไรบางอย่าง lock.unlock (); -วิธีการล็อค () ล็อควัตถุอินสแตนซ์ล็อคดังนั้นเธรดทั้งหมดที่เรียกใช้วิธีการล็อค () บนวัตถุจะถูกบล็อกจนกว่าวิธีการปลดล็อค () ของวัตถุล็อคจะถูกเรียก
ล็อคคืออะไร?
ก่อนที่คำถามนี้เราจะต้องชัดเจน: ไม่ว่าจะมีการเพิ่มคำหลักที่ซิงโครไนซ์ลงในวิธีหรือวัตถุหรือไม่การล็อคที่ได้รับนั้นเป็นวัตถุ ใน Java วัตถุทุกชิ้นสามารถใช้เป็นล็อคซึ่งส่วนใหญ่สะท้อนให้เห็นในสามด้านต่อไปนี้:
สำหรับวิธีการซิงโครไนซ์ล็อคเป็นวัตถุอินสแตนซ์ปัจจุบัน
สำหรับบล็อกวิธีการซิงโครไนซ์ล็อคเป็นวัตถุที่กำหนดค่าไว้ในวงเล็บที่ซิงโคน
สำหรับวิธีการซิงโครไนซ์แบบคงที่ล็อคเป็นวัตถุคลาสของวัตถุปัจจุบัน
ก่อนอื่นมาดูตัวอย่างต่อไปนี้:
คลาสสาธารณะ ThreadTest_01 ใช้งาน RUNNABLE {@Override public synchronized void run () {สำหรับ (int i = 0; i <3; i ++) {system.out.println (thread.currentthread () getName ()+"run ...... "); }} โมฆะคงที่สาธารณะหลัก (สตริง [] args) {สำหรับ (int i = 0; i <5; i ++) {เธรดใหม่ (ใหม่ ThreadTest_01 (), "Thread_"+i) .Start (); -ผลการดำเนินการบางส่วน:
Thread_2run ... Thread_2run ... Thread_4run ... Thread_4run ... Thread_3run ... Thread_3run ... Thread_3run ... Thread_3run ... Thread_2run ... Thread_4run ...
ผลลัพธ์นี้แตกต่างจากผลลัพธ์ที่คาดหวังเล็กน้อย (เธรดเหล่านี้ทำงานรอบ ๆ ที่นี่) การพูดอย่างมีเหตุผลวิธีการเรียกใช้บวกคำหลักที่ซิงโครไนซ์จะสร้างเอฟเฟกต์การซิงโครไนซ์ เธรดเหล่านี้ควรเรียกใช้วิธีการเรียกใช้หนึ่งครั้งหลังจากนั้นอีก ดังที่ได้กล่าวไว้ข้างต้นหลังจากเพิ่มคำหลักที่ซิงโครไนซ์ลงในวิธีการสมาชิกจริง ๆ แล้วมันเป็นการล็อคไปยังวิธีการสมาชิก จุดเฉพาะคือการใช้วัตถุเองที่วิธีการสมาชิกอยู่เป็นล็อควัตถุ อย่างไรก็ตามในตัวอย่างนี้เรามีวัตถุ threadtest 10 ชิ้นใหม่และแต่ละเธรดจะถือล็อควัตถุของวัตถุเธรดของตัวเองซึ่งจะไม่สร้างเอฟเฟกต์แบบซิงโครนัสอย่างแน่นอน ดังนั้น: หากเธรดเหล่านี้จะถูกซิงโครไนซ์วัตถุที่ล็อคโดยเธรดเหล่านี้ควรแบ่งปันและไม่ซ้ำกัน!
วัตถุใดถูกล็อคในเวลานี้? สิ่งที่ล็อคคือการเรียกวัตถุวิธีการแบบซิงโครนัสนี้ กล่าวคือหากวัตถุ threadtest ดำเนินการวิธีการซิงโครไนซ์ในเธรดที่แตกต่างกันมันจะสร้างแบบพิเศษร่วมกัน บรรลุผลของการซิงโครไนซ์ ดังนั้นเปลี่ยนเธรดใหม่ข้างต้น (ใหม่ threadtest_01 (), "thread_" + i) .start (); ถึงเธรดใหม่ (Threadtest, "Thread_" + i) .start ();
สำหรับวิธีการซิงโครไนซ์ล็อคเป็นวัตถุอินสแตนซ์ปัจจุบัน
ตัวอย่างข้างต้นใช้วิธีการซิงโครไนซ์ ลองดูที่บล็อกรหัสที่ซิงโครไนซ์:
คลาสสาธารณะ ThreadTest_02 ขยายเธรด {ล็อคสตริงส่วนตัว; ชื่อสตริงส่วนตัว; Public ThreadTest_02 (ชื่อสตริง, ล็อคสตริง) {this.name = name; this.lock = ล็อค; } @Override โมฆะสาธารณะเรียกใช้ () {ซิงโครไนซ์ (ล็อค) {สำหรับ (int i = 0; i <3; i ++) {system.out.println (ชื่อ+"เรียกใช้ ...... "); }}} โมฆะคงที่สาธารณะหลัก (สตริง [] args) {สตริงล็อค = สตริงใหม่ ("ทดสอบ"); สำหรับ (int i = 0; i <5; i ++) {new ThreadTest_02 ("threadtest_"+i, lock). start (); -ผลการทำงาน:
threadtest_0 run ... threadtest_0 run ... threadtest_0 run ... threadtest_1 run ... threadtest_1 run ... threadtest_1 run ... threadtest_1 run ... threadtest_4 run ... threadtest_4 รัน ...
ในวิธีการหลักเราสร้างล็อควัตถุสตริงและกำหนดวัตถุนี้ให้กับล็อคตัวแปรส่วนตัวของ THREHSTEST2 แต่ละรายการ เรารู้ว่ามีพูลสตริงใน Java ดังนั้นตัวแปรส่วนตัวล็อคของเธรดเหล่านี้จึงชี้ไปที่พื้นที่เดียวกันในหน่วยความจำกองนั่นคือพื้นที่ที่ตัวแปรล็อคในฟังก์ชันหลักถูกเก็บไว้ดังนั้นวัตถุล็อคจึงไม่ซ้ำกันและแชร์ การซิงโครไนซ์เธรด! -
วัตถุสตริงล็อคที่ซิงโครไนซ์ล็อคที่นี่
สำหรับบล็อกวิธีการซิงโครไนซ์ล็อคเป็นวัตถุที่กำหนดค่าไว้ในวงเล็บที่ซิงโคน
คลาสสาธารณะ ThreadTest_03 ขยายเธรด {Public Synchronized Static Static Void Test () {สำหรับ (int i = 0; i <3; i ++) {system.out.println (thread.currentthread (). getName ()+"run ...... "); }} @Override โมฆะสาธารณะ Run () {test (); } โมฆะคงที่สาธารณะหลัก (สตริง [] args) {สำหรับ (int i = 0; i <5; i ++) {ใหม่ ThreadTest_03 (). start (); -ผลการทำงาน:
เธรด -0 รัน ... เธรด -0 รัน ... เธรด -0 รัน ... เธรด -4 รัน ... เธรด -4 รัน ... เธรด -4 รัน ... เธรด -1 รัน ... เธรด -1 รัน ... เธรด -1 รัน ... เธรด -2 รัน ...
ในตัวอย่างนี้วิธีการเรียกใช้ใช้วิธีการซิงโครไนซ์และวิธีการซิงโครไนซ์แบบคงที่ แล้วล็อคที่ซิงโครไนซ์ที่นี่คืออะไร? เรารู้ว่าคงที่อยู่นอกเหนือวัตถุและอยู่ในระดับชั้นเรียน ดังนั้นการล็อควัตถุคืออินสแตนซ์คลาสของคลาสที่มีการปล่อยแบบคงที่ เนื่องจากใน JVM คลาสที่โหลดทั้งหมดมีวัตถุคลาสที่ไม่ซ้ำกันวัตถุ threadtest_03. คลาสเดียวในอินสแตนซ์นี้ ไม่ว่าเราจะสร้างชั้นเรียนกี่ครั้งอินสแตนซ์ของคลาสก็ยังคงเป็นแบบหนึ่ง! ดังนั้นการล็อควัตถุจึงไม่ซ้ำกันและแชร์ การซิงโครไนซ์เธรด! -
สำหรับวิธีการซิงโครไนซ์แบบคงที่ล็อคเป็นวัตถุคลาสของวัตถุปัจจุบัน
หากคลาสกำหนดฟังก์ชั่นสแตติกแบบซิงโครไนซ์ A และฟังก์ชันอินสแตนซ์ที่ซิงโครไนซ์ B ดังนั้น OBJ วัตถุเดียวกันของคลาสนี้จะไม่เป็นการซิงโครไนซ์เมื่อเข้าถึงสองวิธี A และ B ในหลายเธรดเนื่องจากล็อคของพวกเขาแตกต่างกัน การล็อคของวิธี A คือ Object OBJ ในขณะที่ Lock of B คือคลาสที่ OBJ เป็นของ
ล็อคการอัพเกรด
มีสี่รัฐใน Java: สถานะปลอดล็อคสถานะล็อคลำเอียงสถานะล็อคน้ำหนักเบาและสถานะล็อคเฮฟวี่เวทซึ่งจะค่อยๆเพิ่มขึ้นด้วยการแข่งขัน ล็อคสามารถอัพเกรดได้ แต่ไม่สามารถลดระดับได้ซึ่งหมายความว่าการล็อคแบบเอนเอียงไม่สามารถลดระดับเป็นล็อคลำเอียงหลังจากอัปเกรดเป็นล็อคที่มีน้ำหนักเบา กลยุทธ์ของการอัพเกรดล็อค แต่ไม่สามารถลดระดับได้คือการปรับปรุงประสิทธิภาพของการได้รับและปล่อยล็อค ส่วนหลักด้านล่างนี้เป็นบทสรุปของบล็อก: พร้อมกัน (ii) ซิงโครไนซ์ใน Java SE1.6
สปินล็อค
เรารู้ว่าเมื่อเธรดเข้าสู่วิธีการซิงโครไนซ์/บล็อกรหัสหากพบว่าวิธีการซิงโครไนซ์/บล็อกรหัสถูกครอบครองโดยผู้อื่นมันจะรอและป้อนสถานะการบล็อก ประสิทธิภาพของกระบวนการนี้ต่ำ
เมื่อเผชิญหน้ากับการแข่งขันของล็อคหรือรอสิ่งต่าง ๆ เธรดอาจมีความกังวลน้อยกว่าที่จะเข้าสู่สถานะการบล็อก แต่รอและดูว่าล็อคถูกปล่อยออกมาทันทีหรือไม่ นี่คือสปินล็อค ในระดับหนึ่งสปินล็อคสามารถปรับเธรดให้เหมาะสม
ล็อคบวก
ล็อคเชิงบวกส่วนใหญ่จะใช้เพื่อแก้ปัญหาประสิทธิภาพของล็อคโดยไม่ต้องแข่งขัน ในกรณีส่วนใหญ่ล็อคล็อคไม่เพียง แต่ไม่มีการแข่งขันแบบมัลติเธรด แต่จะได้รับหลายครั้งโดยเธรดเดียวกันเสมอ เพื่อที่จะทำให้เธรดได้รับล็อคด้วยต้นทุนที่ต่ำลง เมื่อเธรดได้รับการล็อคเธรดสามารถล็อควัตถุได้หลายครั้ง แต่ทุกครั้งที่ดำเนินการดำเนินการการบริโภคค่าใช้จ่ายบางอย่างเนื่องจากการดำเนินการเปรียบเทียบและการใช้งานของ CPU) เพื่อลดค่าใช้จ่ายนี้ล็อคจะเป็นเธรดแรกที่จะได้รับ หากการล็อคไม่ได้รับโดยเธรดอื่นในระหว่างกระบวนการดำเนินการถัดไปเธรดที่ถือล็อคลำเอียงจะไม่จำเป็นต้องซิงโครไนซ์อีกเลย
เมื่อเธรดอื่น ๆ พยายามที่จะแข่งขันเพื่อล็อคลำเอียงเธรดที่ถือล็อคลำเอียงจะปล่อยล็อค
การขยายตัวล็อค
การโทรหลายครั้งหรือหลายครั้งเพื่อล็อคที่มีความละเอียดน้อยเกินไปนั้นไม่ได้มีประสิทธิภาพเท่ากับการเรียกล็อคที่มีล็อคความละเอียดขนาดใหญ่
ล็อคน้ำหนักเบา
พื้นฐานสำหรับการล็อคน้ำหนักเบาเพื่อปรับปรุงประสิทธิภาพการซิงโครไนซ์ของโปรแกรมคือ "สำหรับล็อคส่วนใหญ่ไม่มีการแข่งขันตลอดวงจรการซิงโครไนซ์" ซึ่งเป็นข้อมูลเชิงประจักษ์ ล็อคที่มีน้ำหนักเบาสร้างพื้นที่ที่เรียกว่าบันทึกล็อคในเฟรมสแต็กของเธรดปัจจุบันซึ่งใช้ในการจัดเก็บจุดชี้ปัจจุบันและสถานะของวัตถุล็อค หากไม่มีการแข่งขันล็อคที่มีน้ำหนักเบาจะใช้การดำเนินการ CAS เพื่อหลีกเลี่ยงค่าใช้จ่ายในการใช้ mutexes แต่ถ้ามีการแข่งขันล็อคนอกเหนือจากค่าใช้จ่ายของ Mutexes การดำเนินการ CAS จะเกิดขึ้นนอกจากนี้ในกรณีของการแข่งขันล็อคน้ำหนักเบาจะช้ากว่าล็อคเฮฟวี่เวทแบบดั้งเดิม
ความยุติธรรมของล็อค
ตรงกันข้ามกับความยุติธรรมคือความหิว แล้ว "ความหิว" คืออะไร? หากเธรดไม่สามารถใช้เวลาทำงานของซีพียูได้เพราะเธรดอื่นมักจะครอบครองซีพียูเสมอเราเรียกเธรดว่า "หิวจนตาย" การแก้ปัญหาความหิวเรียกว่า "ความยุติธรรม" - เธรดทั้งหมดสามารถรับโอกาสในการทำงานของซีพียูได้อย่างเป็นธรรม
มีเหตุผลหลักหลายประการสำหรับความหิวโหย:
เธรดที่มีลำดับความสำคัญสูงใช้เวลา CPU ของเธรดที่มีลำดับความสำคัญต่ำทั้งหมด เราสามารถตั้งค่าลำดับความสำคัญเป็นรายบุคคลสำหรับแต่ละเธรดจาก 1 ถึง 10 ยิ่งมีเธรดลำดับความสำคัญที่สูงขึ้นเท่าไหร่เวลาที่ใช้ในการรับ CPU มากขึ้น สำหรับแอปพลิเคชันส่วนใหญ่จะเป็นการดีที่สุดที่จะไม่เปลี่ยนค่าลำดับความสำคัญ
เธรดถูกบล็อกอย่างถาวรในสถานะที่รอการเข้าสู่บล็อกการซิงโครไนซ์ พื้นที่รหัสซิงโครนัสของ Java เป็นปัจจัยสำคัญที่ทำให้เกิดความหิวโหย บล็อกรหัสซิงโครนัสของ Java ไม่รับประกันลำดับของเธรดที่ป้อน ซึ่งหมายความว่าในทางทฤษฎีมีหนึ่งเธรดหรือมากกว่าที่ถูกบล็อกอยู่เสมอเมื่อพยายามเข้าสู่พื้นที่รหัสแบบซิงโครนัสเพราะเธรดอื่น ๆ มักจะเหนือกว่าพวกเขาเสมอเพื่อให้สามารถเข้าถึงได้ส่งผลให้มันไม่ได้รับโอกาสในการทำงานของซีพียู
เธรดกำลังรอวัตถุที่ตัวเองกำลังรอเสร็จอย่างถาวร หากหลายเธรดอยู่ในการดำเนินการของวิธีการรอ () และการโทรแจ้ง () บนนั้นไม่รับประกันว่าเธรดใด ๆ จะถูกปลุกให้ตื่นเธรดใด ๆ อาจอยู่ในสถานะของการรอคอยอย่างต่อเนื่อง ดังนั้นจึงมีความเสี่ยงที่จะไม่ถูกปลุกให้เป็นด้ายที่รออยู่เพราะกระทู้ที่รอคอยอื่น ๆ สามารถปลุกได้เสมอ
เพื่อแก้ปัญหาของด้าย "ความหิว" เราสามารถใช้ล็อคเพื่อให้บรรลุความยุติธรรม
ความสามารถในการเข้าล็อคอีกครั้ง
เรารู้ว่าเมื่อเธรดร้องขอวัตถุที่ถือล็อคด้วยเธรดอื่นเธรดจะบล็อก แต่จะประสบความสำเร็จได้หรือไม่เมื่อเธรดร้องขอวัตถุที่ถือล็อคด้วยตัวเอง? คำตอบคือความสำเร็จสามารถประสบความสำเร็จและการรับประกันความสำเร็จคือ "กลับเข้ามา" ของล็อคเธรด
"กลับเข้ามาใหม่" หมายความว่าคุณสามารถล็อคภายในของคุณเองอีกครั้งโดยไม่ต้องปิดกั้น ดังนี้:
พ่อชั้นเรียนสาธารณะ {วิธีการที่เป็นโมฆะสาธารณะซิงโครไนซ์ () {// ทำอะไรบางอย่าง}} เด็กชั้นเรียนสาธารณะขยายพ่อ {วิธีโมฆะที่ซิงโครไนซ์สาธารณะ () {// ทำสิ่งที่ super.method (); -
หากไม่ได้กลับเข้ามาใหม่รหัสข้างต้นจะถูกปิดกั้นเนื่องจากวิธีการโทรของเด็ก () จะได้รับการล็อคในตัวของพ่อชั้นเรียนในตัวก่อนแล้วจึงได้รับการล็อคเด็กในตัว เมื่อเรียกวิธีการคลาสแม่คุณจะต้องกลับไปที่ล็อคในตัวของคลาสแม่อีกครั้ง หากไม่ได้กลับมาอีกครั้งคุณอาจตกหลุมรักการหยุดชะงัก
การใช้งานการกลับมาใช้ใหม่ของ Java multithreading คือการเชื่อมโยงการคำนวณคำขอและเธรดที่ใช้งานโดยการล็อคแต่ละครั้ง เมื่อนับเป็น 0 เชื่อว่าการล็อคไม่ได้ถูกครอบครองและจากนั้นเธรดใด ๆ สามารถรับความเป็นเจ้าของล็อคได้ เมื่อเธรดร้องขอได้สำเร็จ JVM จะบันทึกเธรดที่ถือล็อคและตั้งค่านับเป็น 1 หากเธรดอื่นขอล็อคพวกเขาจะต้องรอ เมื่อเธรดร้องขอเพื่อรับล็อคอีกครั้งการนับจะเป็น +1; เมื่อเธรดครอบครองออกจากบล็อกรหัสแบบซิงโครนัสจำนวนจะเป็น -1 จนกว่าจะเป็น 0 ล็อคจะถูกปล่อยออกมา เธรดอื่น ๆ เท่านั้นที่สามารถมีโอกาสได้รับความเป็นเจ้าของล็อค
ล็อคและคลาสการใช้งาน
java.util.concurrent.locks ให้กลไกการล็อคที่ยืดหยุ่นมากโดยให้อินเทอร์เฟซเฟรมเวิร์กและคลาสสำหรับการล็อคและเงื่อนไขการรอคอย มันแตกต่างจากการซิงโครไนซ์ในตัวและจอภาพซึ่งช่วยให้มีความยืดหยุ่นมากขึ้นในการใช้การล็อคและเงื่อนไข แผนภาพโครงสร้างคลาสมีดังนี้:
REENTRANTLOCK: การล็อค mutex reentrant, การใช้งานหลักของอินเตอร์เฟสล็อค
reentrantreadwriteLock:
ReadWriteLock: ReadWriteLock ดูแลคู่ล็อคที่เกี่ยวข้องหนึ่งคู่สำหรับการดำเนินการแบบอ่านอย่างเดียวและอื่น ๆ สำหรับการดำเนินการเขียน
Semaphore: สัญญาณการนับ
เงื่อนไข: วัตถุประสงค์ของการล็อคคือการอนุญาตให้เธรดได้รับการล็อคและดูว่ามีการรอเงื่อนไขที่แน่นอนหรือไม่
Cyclicbarrier: คลาสเสริมแบบซิงโครนัสที่อนุญาตให้กลุ่มของเธรดรอซึ่งกันและกันจนกว่าจะถึงจุดกีดขวางทั่วไป