Countdownlatch เป็นคลาสเครื่องมือที่มีประโยชน์ การใช้มันเราสามารถสกัดกั้นหนึ่งเธรดขึ้นไปเพื่อดำเนินการหลังจากเงื่อนไขที่แน่นอนจะสุก เนื้อหาภายในของมันให้ตัวนับและค่าเริ่มต้นของตัวนับจะต้องระบุเมื่อสร้างล็อคและค่าเริ่มต้นของตัวนับจะต้องมากกว่า 0 นอกจากนี้ยังมีวิธีการนับถอยหลังเพื่อใช้งานค่าตัวนับ ตัวนับจะลดลง 1 ทุกครั้งที่มีการเรียกวิธีการนับถอยหลัง เมื่อค่าตัวนับลดลงเป็น 0 หมายความว่าเงื่อนไขจะสุกและเธรดทั้งหมดถูกบล็อกโดยการเรียกวิธีการรอคอยจะถูกปลุก นี่คือกลไกภายในของ Countdownlatch มันดูง่ายมากไม่มีอะไรมากไปกว่าการปิดกั้นบางเธรดและอนุญาตให้พวกเขาดำเนินการหลังจากถึงเงื่อนไขที่แน่นอน อย่างไรก็ตาม Countdownlatch มีสถานการณ์แอปพลิเคชันที่หลากหลาย ตราบใดที่คุณมีจิตใจที่ยิ่งใหญ่และใช้มันคุณสามารถเล่นเทคนิคต่าง ๆ ได้ สถานการณ์แอปพลิเคชันที่พบบ่อยที่สุดคือการเปิดใช้งานหลายเธรดเพื่อดำเนินงานในเวลาเดียวกันจากนั้นนับและสรุปผลลัพธ์หลังจากดำเนินการงานทั้งหมด รูปต่อไปนี้แสดงให้เห็นถึงกระบวนการทั้งหมดของการปิดกั้นเธรด
รูปด้านบนแสดงให้เห็นว่า 5 เธรดถูกบล็อกโดยเรียกวิธีการรอคอยและพวกเขาจำเป็นต้องรอให้ค่าตัวนับลดลงเป็น 0 ก่อนที่จะดำเนินการต่อ ค่าเริ่มต้นของตัวนับถูกระบุเมื่อสร้างล็อคและลดลงในภายหลัง 1 โดยแต่ละการโทรไปยังวิธีการนับถอยหลัง รหัสต่อไปนี้โพสต์วิธีการก่อสร้าง Countdownlatch
// constructor public countdownlatch (จำนวน int) {ถ้า (นับ <0) โยน unlegalargumentException ใหม่ ("นับ <0"); this.sync = sync ใหม่ (นับ); -Countdownlatch มีตัวสร้างพารามิเตอร์เพียงตัวเดียวและค่าที่มากกว่า 0 จะต้องผ่านเป็นค่าเริ่มต้นของตัวนับมิฉะนั้นจะมีการรายงานข้อผิดพลาด คุณจะเห็นได้ว่าในตัวสร้างเพียงวัตถุซิงค์ใหม่และกำหนดให้กับตัวแปรสมาชิกซิงค์ เช่นเดียวกับคลาสเครื่องมือการซิงโครไนซ์อื่น ๆ การใช้งานของ Countdownlatch ขึ้นอยู่กับ AQS ซึ่งเป็นแอปพลิเคชันในโหมดที่ใช้ร่วมกันของ AQS Countdownlatch ใช้การซิงค์คลาสภายในและใช้เพื่อสืบทอด AQS เพื่อให้สามารถใช้วิธีการส่วนใหญ่ของ AQS มาดูรหัสของคลาส Sync Internal Class
// synchronizer private static คลาสสุดท้าย sync ขยาย abstractqueuedsynchronizer {// constructor sync (จำนวน int) {setState (นับ); } // รับสถานะการซิงโครไนซ์ปัจจุบัน int int getCount () {return getState (); } // พยายามที่จะได้รับการล็อค // ส่งคืนหมายเลขลบ: ระบุว่าเธรดปัจจุบันไม่สามารถรับ // ส่งคืนค่าศูนย์: ระบุว่าเธรดปัจจุบันได้รับสำเร็จแล้ว แต่เธรดที่ตามมาไม่สามารถรับได้อีกต่อไป 1: -1; } // พยายามที่จะปลดปล่อยล็อคบูลีน tryreaseshared (releases int) {สำหรับ (;;) {// รับสถานะการซิงโครไนซ์ int c = getState (); // ถ้าสถานะการซิงโครไนซ์คือ 0, ถ้า (c == 0) {return false; } // มิฉะนั้นลดสถานะการซิงโครไนซ์โดย 1 int nextc = c-1; // ใช้เมธอด CAS เพื่ออัปเดตสถานะการซิงโครไนซ์ IF (PomperEndSetState (C, NextC)) {return nextc == 0; -คุณจะเห็นว่าตัวสร้างของ SYNC จะตั้งค่าของสถานะการซิงโครไนซ์เป็นค่าพารามิเตอร์ที่ผ่าน หลังจากนั้นทุกครั้งที่มีการเรียกวิธีการนับถอยหลังค่าของสถานะซิงโครนัสจะลดลง 1 ซึ่งเป็นหลักการดำเนินการของเคาน์เตอร์ สองวิธีที่ใช้กันมากที่สุดเมื่อใช้คลาสเครื่องมือ Countdownlatch คือวิธีการรอคอยและวิธีการนับถอยหลัง การเรียกใช้วิธีการรอคอยจะบล็อกเธรดปัจจุบันจนกว่าตัวนับคือ 0 และการเรียกใช้วิธีการนับถอยหลังจะลดค่าตัวนับลง 1 จนกว่าจะลดลงเหลือ 0 ลองดูว่าวิธีการรอคอยเรียกใช้อย่างไร
// ทำให้เธรดปัจจุบันรอจนกว่าสลักจะลดลงเป็น 0 หรือเธรดจะถูกขัดจังหวะเป็นโมฆะสาธารณะรอ () พ่น InterruptedException {// การได้รับ sync.acquiresharedinctibleructible (1);} // การล็อคในโหมดขัดจังหวะ (โหมดที่ใช้ร่วมกัน) if (thread.interrupted ()) {โยน interruptedException ใหม่ (); } // 1 ลองรับล็อคถ้า (tryacquireshared (arg) <0) {// 2 หากการได้มาล้มเหลวให้ป้อนวิธีการ doacquiresharedinctibly (arg); -เมื่อเธรดเรียกวิธีการรอคอยจริง ๆ แล้วจะเรียกวิธี AQUIRESHAREDINTINTINTINTINTIBLING อย่างต่อเนื่องของ AQS วิธีนี้ได้รับการล็อคเพื่อตอบสนองต่อการหยุดชะงักของเธรด รหัสสำหรับวิธีนี้จะโพสต์ด้านบน เราจะเห็นได้ว่าในวิธีการซื้ออย่างต่อเนื่องก่อนอื่นมันจะเรียกวิธีการ tryacquireshared เพื่อพยายามรับการล็อค เราเห็นตรรกะของวิธี tryacquireshared ที่เขียนใหม่ในการซิงค์ ตรรกะการใช้งานของวิธีการนั้นง่ายมากซึ่งก็คือการตัดสินว่าสถานะการซิงโครไนซ์ปัจจุบันคือ 0 ถ้าเป็น 0, return 1 หมายความว่าสามารถรับล็อคได้หรือไม่มิฉะนั้นจะส่งคืน -1 หมายความว่าไม่สามารถรับล็อคได้ หากวิธีการ tryacquireshared ส่งคืน 1 เธรดสามารถดำเนินการต่อไปโดยไม่ต้องรอ หาก -1 ถูกส่งคืนวิธีการ doacquiresharedinctibly จะถูกเรียกในคิวแบบซิงโครนัสเพื่อรอ นี่คือหลักการที่เรียกวิธีการรอคอยจะบล็อกเธรดปัจจุบัน มาดูกันว่าวิธีการนับถอยหลังจะปลุกเธรดบล็อกอย่างไร
// วิธีการลดการนับถอยหลังสาธารณะ latch public () {sync.releaseshared (1);} // การดำเนินการรีลีส (โหมดที่ใช้ร่วมกัน) สาธารณะบูลีนสุดท้าย releaseshared (int arg) {// 1 ลองปล่อยล็อคถ้า (tryreleaseshared (arg)) {// 2 หากการเปิดตัวสำเร็จ กลับมาจริง; } return false;}คุณจะเห็นว่าวิธีการ releaseshared เรียกในวิธีการนับถอยหลัง วิธีนี้ยังเป็นวิธีการใน AQS นอกจากนี้เรายังโพสต์รหัสของมัน สิ่งแรกในวิธี releaseshared คือการเรียกใช้วิธี tryreleaseshared เพื่อพยายามปล่อยล็อค วิธีการ tryreaseshared เป็นวิธีนามธรรมใน AQS ตรรกะการใช้งานที่เฉพาะเจาะจงอยู่ในคลาส sync sync เราสามารถค้นหาวิธีนี้ในรหัสคลาสซิงค์ที่โพสต์ด้านบน หากวิธีการ tryreaseshared ส่งคืนจริงเพื่อปล่อยและส่งคืน false เพื่อปล่อยความล้มเหลว มันจะกลับมาเป็นจริงหากสถานะการซิงโครไนซ์เป็น 0 หลังจากลดลง 1 ในกรณีอื่น ๆ เท็จจะถูกส่งคืน จากนั้นเมื่อ tryreleaseshared ส่งคืนจริงวิธี Doreleaseshared จะถูกเรียกทันทีเพื่อปลุกเธรดทั้งหมดในคิวการซิงโครไนซ์ สิ่งนี้อธิบายได้ว่าทำไมครั้งสุดท้ายที่วิธีการนับถอยหลังถูกเรียกให้ลดตัวนับเป็น 0 จะปลุกเธรดที่ถูกบล็อกทั้งหมด นี่คือหลักการพื้นฐานของ Countdownlatch มาดูตัวอย่างการใช้งาน
สถานการณ์แอปพลิเคชัน: เมื่อเล่น Happy Landlord คุณต้องรอให้ผู้เล่นทั้งสามคนมาถึงก่อนที่คุณจะสามารถจัดการการ์ดได้
ผู้เล่นระดับสาธารณะขยายเธรด {จำนวน int คงที่ส่วนตัว = 1; ID int สุดท้ายส่วนตัว = นับ ++; ลัทช์นับถอยหลังส่วนตัว; ผู้เล่นสาธารณะ (Countdownlatch latch) {this.latch = latch; } @Override โมฆะสาธารณะเรียกใช้ () {system.out.println ("【 player" + id + "] รายการ"); latch.countdown (); } โมฆะคงที่สาธารณะหลัก (String [] args) พ่น InterruptedException {Countdownlatch latch = New CountdownLatch (3); System.out.println ("เกมเริ่มต้นรอให้ผู้เล่นเข้าสู่ ... "); ผู้เล่นใหม่ (latch). start (); ผู้เล่นใหม่ (latch). start (); ผู้เล่นใหม่ (latch). start (); latch.await (); System.out.println ("ผู้เล่นมาถึงแล้วเริ่มจัดการ ... "); -ผลการดำเนินงานแสดงให้เห็นว่าการดำเนินการซื้อขายจะต้องดำเนินการหลังจากผู้เล่นทุกคนเข้าสู่สนาม เราแสดงความคิดเห็นออก 23 บรรทัด latch.await () และเปรียบเทียบเพื่อดูผลลัพธ์
คุณจะเห็นได้ว่าหลังจากแสดงความคิดเห็น LINE LATCH.AAT () จะไม่รับประกันว่าผู้เล่นทุกคนจะเริ่มจัดการการ์ดหลังจากเข้าสู่สนามเท่านั้น
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น