เห็นได้ชัดว่าnotifyตื่น (มี) หนึ่งเธรดในชุดการรอnotifyAllตื่นกระทู้ทั้งหมดในชุดการรอ การสนทนาต่อไปนี้ควรกำจัดข้อสงสัยใด ๆ notifyAllควรใช้เวลาส่วนใหญ่ หากคุณไม่แน่ใจว่าจะใช้อะไรให้ใช้notifyAllโปรดดูคำอธิบายที่ตามมา
อ่านอย่างระมัดระวังและเข้าใจ กรุณาส่งอีเมลฉันหากคุณมีคำถามใด ๆ
ดูโปรดิวเซอร์ / ผู้บริโภค (สมมติว่าคลาส ProducerConsumer มีสองวิธี) มันแย่ (เพราะมันใช้notify) - ใช่มันอาจใช้ได้ - แม้เวลาส่วนใหญ่ แต่มันก็อาจทำให้เกิดการหยุดชะงักได้ - เราจะเห็นว่าทำไม:
public synchronized void put(Object o) {
    while (buf.size()==MAX_SIZE) {
        wait(); // called if the buffer is full (try/catch removed for brevity)
    }
    buf.add(o);
    notify(); // called in case there are any getters or putters waiting
}
public synchronized Object get() {
    // Y: this is where C2 tries to acquire the lock (i.e. at the beginning of the method)
    while (buf.size()==0) {
        wait(); // called if the buffer is empty (try/catch removed for brevity)
        // X: this is where C1 tries to re-acquire the lock (see below)
    }
    Object o = buf.remove(0);
    notify(); // called if there are any getters or putters waiting
    return o;
}
ประการแรก
ทำไมเราต้องใช้ขณะที่วนรอบการรอ?
เราต้องการการwhileวนซ้ำในกรณีที่เราได้รับสถานการณ์นี้:
ผู้บริโภค 1 (C1) เข้าสู่บล็อกที่ซิงโครไนซ์และบัฟเฟอร์ว่างเปล่าดังนั้น C1 จะอยู่ในชุดการรอ (ผ่านการwaitโทร) ผู้บริโภค 2 (C2) กำลังจะเข้าสู่วิธีการทำข้อมูลให้ตรงกัน (ที่จุด Y ข้างต้น) แต่ผู้ผลิต P1 notifyทำให้วัตถุในบัฟเฟอร์และบริการโทรภายหลัง เธรดที่รออยู่เพียง C1 เท่านั้นจึงถูกปลุกและตอนนี้พยายามรับการล็อกวัตถุอีกครั้งที่จุด X (ด้านบน)
ตอนนี้ C1 และ C2 กำลังพยายามรับการล็อกการซิงโครไนซ์ หนึ่งในนั้น (nondeterministically) ถูกเลือกและเข้าสู่วิธีการอื่นถูกบล็อก (ไม่รอ - แต่ถูกบล็อกพยายามรับการล็อกบนเมธอด) สมมติว่า C2 ได้รับการล็อคก่อน C1 ยังคงปิดกั้น (พยายามรับการล็อกที่ X) C2 เสร็จสิ้นวิธีการและปลดล็อค ตอนนี้ C1 ได้รับล็อค เดาสิว่าโชคดีที่เรามีwhileลูปเพราะ C1 ทำการตรวจสอบลูป (การ์ด) และป้องกันไม่ให้ลบองค์ประกอบที่ไม่มีอยู่ออกจากบัฟเฟอร์ (C2 ได้รับแล้ว!) หากเราไม่มี a whileเราจะได้ค่าIndexArrayOutOfBoundsExceptionเป็น C1 พยายามลบองค์ประกอบแรกออกจากบัฟเฟอร์!
ตอนนี้
ตกลงตอนนี้ทำไมเราต้องแจ้งทั้งหมด
ในตัวอย่างผู้ผลิต / ผู้บริโภคด้านบนดูเหมือนว่าเราสามารถไปnotifyได้ ดูเหมือนว่าด้วยวิธีนี้เพราะเราสามารถพิสูจน์ได้ว่าผู้คุมในห่วงการรอคอยสำหรับผู้ผลิตและผู้บริโภคนั้นไม่เหมือนกัน นั่นคือดูเหมือนว่าเราไม่สามารถมีเธรดที่กำลังรอในputวิธีการและgetวิธีการได้เนื่องจากเพื่อให้เป็นจริงแล้วสิ่งต่อไปนี้จะต้องเป็นจริง:
buf.size() == 0 AND buf.size() == MAX_SIZE (สมมติว่า MAX_SIZE ไม่ใช่ 0)
notifyAllแต่นี้เป็นพอไม่ดีเราจำเป็นต้องใช้ มาดูกันว่าทำไม ...
สมมติว่าเรามีบัฟเฟอร์ขนาด 1 (เพื่อให้ง่ายต่อการปฏิบัติตามตัวอย่าง) ขั้นตอนต่อไปนี้นำเราไปสู่การหยุดชะงัก โปรดทราบว่าเมื่อใดก็ตามที่เธรดถูกปลุกด้วยการแจ้งเตือนสามารถเลือก JVM แบบไม่กำหนดค่าล่วงหน้าได้ - ซึ่งเป็นเธรดที่รอใด ๆ สามารถถูกปลุกได้ นอกจากนี้โปรดทราบว่าเมื่อหลายเธรดกำลังบล็อกการเข้าสู่วิธีการ (เช่นพยายามรับการล็อค) ลำดับของการได้มานั้นไม่สามารถกำหนดได้ โปรดจำไว้ว่าเธรดสามารถอยู่ในวิธีใดวิธีหนึ่งในแต่ละครั้งเท่านั้นวิธีการที่ซิงโครไนซ์อนุญาตให้เธรดเพียงหนึ่งเดียวเท่านั้นที่จะดำเนินการ หากลำดับเหตุการณ์ต่อไปนี้เกิดขึ้น - ผลลัพธ์การหยุดชะงัก:
ขั้นตอนที่ 1:
 
- P1 ใส่ 1 อักขระลงในบัฟเฟอร์
ขั้นตอนที่ 2:
 
- ความพยายาม P2 ครั้งput- ตรวจสอบการรอลูป - ถ่านเรียบร้อยแล้วรอ
ขั้นตอนที่ 3:
 
- ความพยายาม P3 put- ตรวจสอบการรอวน - ตัวอักษรรอแล้ว
ขั้นตอนที่ 4:
 
- C1 พยายามที่จะได้รับ 1 ถ่าน
- C2 พยายามที่จะได้รับ 1 ถ่าน - บล็อกในการเข้าสู่getวิธีการ
- C3 พยายามที่จะได้รับ 1 ถ่าน - บล็อกเมื่อเข้าสู่getวิธีการ
ขั้นตอนที่ 5:
 
- C1 กำลังดำเนินการgetเมธอด - รับตัวถ่าน, การเรียกnotify, ออกจากเมธอด
- การnotifyตื่นขึ้น P2 
- แต่, C2 เข้าสู่วิธีการก่อนที่ P2 จะสามารถ (P2 ต้อง reacquire ล็อค) ดังนั้น P2 บล็อกเมื่อเข้าสู่putวิธีการ
- C2 ตรวจสอบลูปรอไม่มีตัวอักษรในบัฟเฟอร์ดังนั้นรอ
- C3 เข้าสู่วิธีหลังจาก C2 แต่ก่อน P2 ตรวจสอบลูปรอไม่มีตัวอักษรในบัฟเฟอร์อีกต่อไปรอ
ขั้นตอนที่ 6:
 
- ตอนนี้: มี P3, C2 และ C3 รออยู่! 
- ในที่สุด P2 ได้มาล็อคใส่ถ่านในบัฟเฟอร์โทรแจ้งเตือนออกจากวิธีการ
ขั้นตอนที่ 7:
 
- การแจ้งเตือนของ P2 ทำให้ P3 ตื่นขึ้นมา (โปรดจำไว้ว่าเธรดใด ๆ สามารถถูกปลุกได้) 
- P3 ตรวจสอบเงื่อนไขการวนรอบการรอซึ่งมีอักขระอยู่ในบัฟเฟอร์อยู่แล้วดังนั้นรอ 
- ไม่มีอีกต่อไปที่เรียกว่าข้อความและสามหัวข้อระงับอย่างถาวร!
การแก้ไข: แทนที่notifyด้วยnotifyAllในรหัสผู้ผลิต / ผู้บริโภค (ด้านบน)