ตั้งแต่ Java 5 แพ็คเกจ java.util.concurrent.locks มีการใช้งานล็อคบางอย่างดังนั้นคุณไม่จำเป็นต้องใช้ล็อคของคุณเองอีกต่อไป แต่คุณยังต้องเข้าใจวิธีการใช้ล็อคเหล่านี้
ล็อคง่ายๆ
เริ่มต้นด้วยบล็อกการซิงโครไนซ์ใน Java:
เคาน์เตอร์คลาสสาธารณะ {จำนวน int ส่วนตัว = 0; สาธารณะ int inc () {ซิงโครไนซ์ (นี่) {return ++ count; -คุณจะเห็นว่ามีบล็อกรหัสที่ซิงโครไนซ์ (นี้) ในเมธอด Inc () บล็อกรหัสนี้สามารถตรวจสอบให้แน่ใจว่ามีเพียงเธรดเดียวเท่านั้นที่สามารถเรียกใช้ Return ++ Count ได้ในเวลาเดียวกัน แม้ว่ารหัสในบล็อกซิงโครไนซ์ซิงโครไนซ์จะซับซ้อนมากขึ้น แต่การทำงานอย่างง่ายของการนับ ++ ก็เพียงพอที่จะแสดงความหมายของการซิงโครไนซ์เธรด
คลาสเคาน์เตอร์ต่อไปนี้ใช้ล็อคแทนการซิงโครไนซ์เพื่อให้บรรลุเป้าหมายเดียวกัน:
ตัวนับคลาสสาธารณะ {ล็อคส่วนตัว = ล็อคใหม่ (); จำนวน int ส่วนตัว = 0; Public Int Inc () {lock.lock (); int newCount = ++ นับ; lock.unlock (); คืนใหม่; -วิธีการล็อค () ล็อควัตถุอินสแตนซ์ล็อคดังนั้นเธรดทั้งหมดที่เรียกใช้วิธีการล็อค () บนวัตถุจะถูกบล็อกจนกว่าวิธีการปลดล็อค () ของวัตถุล็อคจะถูกเรียก
นี่คือการใช้งานง่าย ๆ ของคลาสล็อค:
เคาน์เตอร์ระดับสาธารณะ {ล็อคคลาสสาธารณะ {บูลีนส่วนตัว islocked = false; โมฆะที่ซิงโครไนซ์ล็อค () พ่น InterruptedException {ในขณะที่ (islocked) {wait (); } islocked = true; } โมฆะที่ซิงโครไนซ์สาธารณะปลดล็อค () {islocked = false; แจ้ง(); -หมายเหตุในขณะที่ (islocked) วนอยู่ภายในซึ่งเรียกอีกอย่างว่า "สปินล็อค" เมื่อ islocked เป็นจริงบล็อกการเรียกใช้เธรดล็อค () และรอการโทร () การโทร () เพื่อป้องกันไม่ให้เธรดกลับมาจากการรอคอย () โดยไม่ได้รับการแจ้งเตือน () การโทร (เรียกอีกอย่างว่าการปลุกเท็จ) เธรดจะตรวจสอบเงื่อนไขที่ถูกล็อคอีกครั้งเพื่อตรวจสอบว่าสามารถดำเนินการต่อไปได้อย่างปลอดภัยหรือต้องการรออีกครั้งแทนที่จะคิดว่าเธรดสามารถดำเนินการต่อไปได้อย่างปลอดภัย หาก Islocked เป็นเท็จเธรดปัจจุบันจะออกจากการวนซ้ำ (islocked) ในขณะที่ (islocked) และตั้งค่า islocked กลับเป็น TRUE เพื่อให้เธรดอื่น ๆ ที่เรียกวิธีการล็อค () สามารถเพิ่มล็อคบนอินสแตนซ์ล็อค
เมื่อเธรดเสร็จสิ้นรหัสในส่วนวิกฤต (อยู่ระหว่างล็อค () และปลดล็อค ()) ปลดล็อค () เรียกว่า การดำเนินการของ Unlock () จะตั้งค่า islocked เป็นเท็จและแจ้งเตือน (ตื่น) หนึ่งในเธรดที่เรียกว่าฟังก์ชัน Wait () ในวิธีการล็อค () และอยู่ในสถานะรอ
ความสามารถในการเข้าล็อคอีกครั้ง
บล็อกซิงโครไนซ์ซิงโครไนซ์ใน Java นั้นกลับมาอีกครั้ง ซึ่งหมายความว่าหากเธรด Java เข้าสู่บล็อกซิงโครไนซ์ซิงโครไนซ์ในรหัสและทำให้ได้ล็อคบนท่อที่สอดคล้องกับวัตถุการซิงโครไนซ์ที่ใช้โดยบล็อกซิงโครไนซ์แล้วเธรดสามารถป้อนบล็อกรหัส Java อื่นที่ซิงโครไนซ์โดยวัตถุท่อเดียวกัน นี่คือตัวอย่าง:
ชั้นเรียนสาธารณะ reentrant {สาธารณะที่ซิงโครไนซ์ด้านนอก () {inner (); } public synchronized inner () {// do something}}โปรดทราบว่าทั้ง Outer () และ Inner () ได้รับการประกาศให้ซิงโครไนซ์ซึ่งเทียบเท่ากับบล็อกซิงโครไนซ์ (นี้) ใน Java หากเธรดเรียกว่า Outer () ไม่มีปัญหาในการโทรเข้า () ใน Outer () เนื่องจากทั้งสองวิธี (บล็อกโค้ด) ถูกซิงโครไนซ์โดยวัตถุการจัดการเดียวกัน ("นี่") หากเธรดมีการล็อคบนวัตถุท่อแล้วจะสามารถเข้าถึงบล็อกรหัสทั้งหมดที่ซิงโครไนซ์โดยวัตถุท่อ นี่คืออีกครั้ง เธรดสามารถป้อนบล็อกของรหัสใด ๆ ที่ซิงโครไนซ์โดยล็อคที่มีอยู่แล้ว
การใช้งานล็อคที่ให้ไว้ข้างต้นไม่ได้กลับมาอีกครั้ง หากเราเขียนคลาส reentrant ใหม่ดังต่อไปนี้เมื่อเธรดเรียกว่า Outer () มันจะบล็อกที่ lock.lock () ของเมธอด inner ()
คลาสสาธารณะ reentrant2 {ล็อคล็อค = ล็อคใหม่ (); Public Outer () {lock.lock (); ด้านใน (); lock.unlock (); } สาธารณะที่ซิงโครไนซ์ด้านใน () {lock.lock (); // ทำอะไรบางอย่าง lock.unlock (); -เธรดที่เรียกว่า OUTER () จะล็อคอินสแตนซ์ล็อคก่อนจากนั้นโทรต่อเพื่อโทรเข้าด้านใน () ในเมธอด inner () เธรดจะพยายามล็อคอินสแตนซ์ล็อคอีกครั้งและการกระทำจะล้มเหลว (นั่นคือเธรดจะถูกบล็อก) เนื่องจากอินสแตนซ์ล็อคถูกล็อคอยู่แล้วในเมธอด Outer ()
หาก Unlock () ไม่ได้ถูกเรียกระหว่าง Lock () สองครั้งการโทรครั้งที่สองเพื่อล็อคจะบล็อก หลังจากเห็นการใช้งาน Lock () คุณจะพบว่าเหตุผลนั้นชัดเจน:
ล็อคคลาสสาธารณะ {บูลีน islocked = false; โมฆะที่ซิงโครไนซ์ล็อค () พ่น InterruptedException {ในขณะที่ (islocked) {wait (); } islocked = true; -ไม่ว่าจะเป็นเธรดที่จะออกจากวิธีการล็อค () จะถูกกำหนดโดยเงื่อนไขในขณะที่ลูป (สปินล็อค) เงื่อนไขการตัดสินในปัจจุบันคือการดำเนินการล็อคได้รับอนุญาตเฉพาะเมื่อ islocked เป็นเท็จโดยไม่พิจารณาว่าเธรดใดล็อคมัน
เพื่อที่จะทำให้คลาสล็อคนี้สามารถกลับมาได้ใหม่เราจำเป็นต้องทำการเปลี่ยนแปลงเล็กน้อย:
ล็อคคลาสสาธารณะ {บูลีน islocked = false; ด้ายล็อค by = null; int lockedCount = 0; โมฆะที่ซิงโครไนซ์สาธารณะล็อค () พ่น InterruptedException {เธรด callyThread = thread.currentThread (); ในขณะที่ (islocked && lockedby! = callingThread) {wait (); } islocked = true; LockedCount ++; LockedBy = CallingThread; } โมฆะที่ซิงโครไนซ์สาธารณะปลดล็อค () {ถ้า (thread.currentthread () == this.lockedby) {lockedCount--; if (lockedCount == 0) {islocked = false; แจ้ง(); -โปรดทราบว่ากระแสในขณะที่ลูป (สปินล็อค) คำนึงถึงเธรดที่ล็อคอินสแตนซ์ล็อค หากวัตถุล็อคปัจจุบันไม่ล็อค (islocked = false) หรือเธรดการเรียกปัจจุบันได้ล็อคอินสแตนซ์ล็อคแล้วในขณะที่ลูปจะไม่ถูกเรียกใช้งานและการล็อคการเรียกเธรด () สามารถออกจากวิธีการ (หมายเหตุของนักแปล: "อนุญาตให้ออกจากวิธี" ในความหมายปัจจุบัน
นอกจากนี้เราจำเป็นต้องบันทึกจำนวนครั้งที่เธรดเดียวกันล็อควัตถุล็อคซ้ำ ๆ ซ้ำ ๆ มิฉะนั้นการโทรออก () หนึ่งครั้งจะปลดบล็อกล็อคทั้งหมดแม้ว่าล็อคปัจจุบันจะถูกล็อคหลายครั้ง เราไม่ต้องการให้การล็อคปลดล็อคจนกว่าการโทรปลดล็อค () จะถึงจำนวนครั้งที่เรียกว่าการล็อค () ที่สอดคล้องกันเรียกว่า
ตอนนี้คลาสล็อคนี้กลับมาอีกครั้ง
ความยุติธรรมของล็อค
บล็อกที่ซิงโครไนซ์ของ Java ไม่รับประกันคำสั่งที่เธรดพยายามป้อน ดังนั้นหากหลายเธรดยังคงแข่งขันเพื่อเข้าถึงบล็อกซิงโครไนซ์ซิงโครไนซ์เดียวกันมีความเสี่ยงที่เธรดอย่างน้อยหนึ่งเธรดจะไม่สามารถเข้าถึงได้นั่นคือการเข้าถึงจะถูกกำหนดให้กับเธรดอื่นเสมอ สถานการณ์นี้เรียกว่า Thread Hunger เพื่อหลีกเลี่ยงปัญหานี้ล็อคจำเป็นต้องบรรลุความเป็นธรรม ล็อคที่แสดงในบทความนี้มีการใช้งานภายในด้วยบล็อกซิงโครไนซ์ซิงโครไนซ์ดังนั้นจึงไม่รับประกันว่าจะยุติธรรม
Call Unlock () ในคำสั่งสุดท้าย
หากการล็อคถูกใช้เพื่อปกป้องพื้นที่วิกฤตและพื้นที่วิกฤตอาจมีข้อยกเว้นเป็นสิ่งสำคัญมากที่จะโทรออก () ในคำสั่งสุดท้าย สิ่งนี้ทำให้มั่นใจได้ว่าวัตถุล็อคสามารถปลดล็อคได้เพื่อให้เธรดอื่นสามารถล็อคได้ต่อไป นี่คือตัวอย่าง:
lock.lock (); ลอง {// do critical code code, // ซึ่งอาจโยนข้อยกเว้น} ในที่สุด {lock.unlock ();}โครงสร้างที่เรียบง่ายนี้ช่วยให้มั่นใจได้ว่าวัตถุล็อคสามารถปลดล็อคได้เมื่อมีการโยนข้อยกเว้นในพื้นที่วิกฤต หาก Unlock () ไม่ได้ถูกเรียกในคำสั่งสุดท้ายเมื่อมีการโยนข้อยกเว้นในส่วนวิกฤตวัตถุล็อคจะยังคงอยู่ในสถานะล็อคตลอดไปซึ่งจะทำให้เธรดอื่น ๆ ทั้งหมดเรียกล็อค () บนวัตถุล็อคเพื่อบล็อก
ข้างต้นคือข้อมูลเกี่ยวกับการล็อคแบบมัลติเธรด Java เราจะยังคงเพิ่มข้อมูลที่เกี่ยวข้องในอนาคต ขอบคุณสำหรับการสนับสนุนเว็บไซต์นี้!