ความแตกต่างระหว่าง wait () และ sleep ()


1203

ความแตกต่างระหว่าง a wait()และsleep()ในเธรดคืออะไร?

ฉันเข้าใจหรือไม่ว่าwait()-ing Thread ยังคงอยู่ในโหมดใช้งานและใช้รอบ CPU แต่sleep()-ing ไม่ได้ใช้ CPU รอบใดถูกต้องหรือไม่

เหตุใดเราจึงมีทั้ง wait()และsleep(): การใช้งานของพวกเขาแตกต่างกันในระดับที่ต่ำกว่าอย่างไร


50
คำถามที่ดีมาก ความหมายของทั้งสองง่ายต่อการสับสน
Andreas Petersson

1
คำถามที่ดีมาก แต่พวกเขาเป็น 2 ในหนึ่ง เหตุใดเราจึงมีทั้งสองอย่างไม่เหมือนกันกับที่พวกเขาสามารถนำไปใช้ (และไม่ใช่!) ในระดับที่ต่ำกว่า ฉันก็ตอบไปเหมือนกัน
estani

สมมติว่าเธรด A อยู่ในบล็อกที่ซิงโครไนซ์และในขณะที่มันอยู่ใน cpu จากเธรดนี้จะถูกนำไปให้กับเธรด B อื่นซึ่งขณะนี้อยู่ในสถานะที่เธรด A จะไปเธรดอื่น ๆ ที่รอบล็อกที่ซิงโครไนซ์นี้จะเข้ามา ?
ปีเตอร์

1
นี่เป็นบทความที่ดีที่อธิบายว่า: qat.com/using-waitnotify-instead-thread-sleep-java
Triton Man

3
EXCATLY ตรงกันข้าม - sleep "ใช้" CPU-cycles ที่มีอยู่ทั้งหมด แต่เนื่องจาก thread จะอยู่ใน "WAITING" - state สิ่งเหล่านี้สามารถให้ผลได้หากจำเป็น - ในความเป็นจริงระบบปฏิบัติการส่วนใหญ่จะให้วงจรโดยอัตโนมัติถ้าเป็นไปได้ดังนั้น เธรดของคุณจะไม่สร้างโหลด CPU จริง ๆ ... แต่จะทำเช่นนั้นกับระบบปฏิบัติการรุ่นเก่า ในทางกลับกัน Object.wait () ไม่เคยใช้รอบใด ๆ (ในขณะที่ไม่ได้ถูกสังเกตเห็น) เพราะสิ่งนั้นเกิดขึ้นจริงผ่านการขัดจังหวะโดยซอฟต์แวร์ในหลาย ๆ กรณี - การล็อคส่วนตัวชั่วคราวและโปร่งใสดำเนินการโดย JVM Thread.sleep เป็นการปฏิบัติที่ไม่ดี
specializt

คำตอบ:


837

A waitสามารถ "ปลุก" โดยการเรียกเธรดอื่นnotifyบนจอภาพที่กำลังรออยู่ในขณะที่ a sleepไม่สามารถทำได้ นอกจากนี้จะต้องมีwait(และnotify) เกิดขึ้นในบล็อกsynchronizedบนวัตถุมอนิเตอร์ในขณะที่sleepไม่:

Object mon = ...;
synchronized (mon) {
    mon.wait();
} 

ณ จุดนี้ในขณะนี้การดำเนินการรอด้ายและรุ่นจอภาพ หัวข้ออื่นอาจทำ

synchronized (mon) { mon.notify(); }

(บนmonวัตถุเดียวกัน) และเธรดแรก (สมมติว่าเป็นเธรดที่รออยู่บนจอภาพเท่านั้น) จะปลุก

คุณยังสามารถโทรได้notifyAllหากมีมากกว่าหนึ่งเธรดที่กำลังรอบนจอภาพ - สิ่งนี้จะปลุกพวกเขาทั้งหมด อย่างไรก็ตามมีเพียงหนึ่งเธรดเท่านั้นที่จะสามารถจับจอแสดงผล (โปรดจำไว้ว่าwaitในsynchronizedบล็อก) และดำเนินการต่อ - ส่วนอื่น ๆ จะถูกบล็อกจนกว่าพวกเขาจะได้รับการล็อคของจอภาพ

ประเด็นก็คือว่าคุณโทรwaitในObjectตัวเอง (เช่นคุณรอบนจอภาพของวัตถุ) ในขณะที่คุณเรียกบนsleepThread

อีกประเด็นหนึ่งคือคุณจะได้รับสัญญาณเตือนปลอมจากwait(เช่นข้อความที่กำลังรอดำเนินการต่อโดยไม่มีเหตุผลที่ชัดเจน) คุณควรจะเสมอwaitในขณะที่ปั่นบนเงื่อนไขบางอย่างดังต่อไปนี้:

synchronized {
    while (!condition) { mon.wait(); }
}

131
ไม่มันไม่สามารถ มันสามารถถูกขัดจังหวะเท่านั้น
ปีเตอร์ibrtibraný

9
เมื่อคุณขัดจังหวะคุณจะต้องรู้ว่าคุณต้องการใช้เธรดใด เมื่อคุณโทรแจ้งเตือนคุณต้องมีวัตถุและคุณไม่สนใจว่าจะมีเธรดอื่นใดที่ 'รอ' อยู่บนวัตถุนี้หรือไม่ wait / แจ้งเตือนใช้สำหรับการสื่อสารในขณะที่ sleep ใช้สำหรับ ehm, sleep
ปีเตอร์ibrtibraný

28
@Geek - ทำไมคุณถึงพูดในโลกรอ () เสียรอบ CPU?
Robert Munteanu

25
การขัดจังหวะมีวัตถุประสงค์เพื่อเป็นกลไกในการกระตุ้นให้เธรดหยุดทำงานอย่างช้า ๆ และยกเลิกการดำเนินการที่เหลืออยู่ wait/ notifyโดยทั่วไปจะใช้เพื่อรอเธรดอื่น ๆ เพื่อให้งานสำเร็จหรือรอจนกว่าเงื่อนไขบางประการจะเป็นที่พอใจ
Louis Wasserman

13
ฉันอ่านคำตอบทั้งหมด แต่ฉันยังรู้สึกถึงข้อมูลที่หายไปเล็กน้อย หลายคนเขียนคำจำกัดความจาก Javadoc และความหมายของคำสองคำภาษาอังกฤษ แต่ฉันไม่เห็นทำไมฉันจึงควรใช้การนอนหลับแทนที่จะรอ? การเปรียบเทียบและความแตกต่างระหว่างความเร็วทั้งสองคืออะไร ถ้าฉันสามารถทำทุกอย่างที่ฉันสามารถทำได้ด้วยการนอนหลับทำไมฉันจึงควรเลือกที่จะนอน?
Balazs Zsoldos

334

ความแตกต่างที่สำคัญอย่างหนึ่งที่ยังไม่ได้กล่าวถึงคือในขณะที่การนอนหลับเธรดไม่ปล่อยการล็อกที่เก็บไว้ในขณะที่รอการปล่อยการล็อกบนวัตถุที่wait()เรียกใช้

synchronized(LOCK) {
    Thread.sleep(1000); // LOCK is held
}


synchronized(LOCK) {
    LOCK.wait(); // LOCK is not held
}

105
การรอเพียงปลดล็อคสำหรับวัตถุที่คุณโทรรอ () เปิด มันไม่ได้ปลดล็อคอื่น ๆ
Jon Skeet

16
คุณไม่จำเป็นต้องโทรหา sleep จากภายในล็อค - ล็อคและรอ / แจ้งให้ทราบล่วงหน้า แต่การล็อคและ sleep นั้นไม่เกี่ยวข้องกัน
oxbow_lakes

7
@oxbow_lakes - ฉันจะบอกว่าคุณไม่ควรนอนด้วยระบบล็อคมีบางกรณีที่ใช้งานได้ แค่ต้องการชี้ให้เห็นความแตกต่าง
Robert Munteanu

5
@RobertMunteanu คำตอบของคุณทำให้เข้าใจผิดอ้างว่าsleepถือล็อคJavaแต่ไม่ได้ ที่จะมีการเปรียบเทียบยุติธรรมเราจะเปรียบเทียบsynchronized(OUTER_LOCK){ Thread.sleep(1000); }กับและเราจะเห็นได้ว่าคำแนะนำทั้งไม่ปล่อยsynchronized(OUTER_LOCK){ synchronized(LOCK){LOCK.wait();} } OUTER_LOCKหากมีความแตกต่างใด ๆ เราสามารถพูดsleepได้ว่าไม่ได้ใช้การ ล็อกjavaอย่างชัดเจนแต่คำถามถามเกี่ยวกับเครื่องหมายคำพูด ไม่ได้นำมาอ้าง
Pacerier

2
@Pacerier wait()เกี่ยวข้องกับเงื่อนไขของการล็อกส่วนใหญ่ที่ถูกเรียกจากตัวอย่างรหัสของคุณwait()สามารถปล่อยLOCKได้OUTER_LOCKเท่านั้น นั่นคือวิธีการออกแบบจอภาพ Java การเปรียบเทียบยุติธรรมจะเป็นและsynchronized(OUTER_LOCK){ synchronized(LOCK) { Thread.sleep(1000); } } synchronized(OUTER_LOCK){ synchronized(LOCK) { LOCK.wait(); } }ในกรณีนี้sleep()จะล็อคทั้งสองในขณะที่wait()จะปล่อยLOCKแต่ยังคงค้างอยู่OUTER_LOCK
Dan

243

ฉันพบว่าโพสต์นี้มีประโยชน์ มันทำให้ความแตกต่างระหว่างThread.sleep(), Thread.yield()และObject.wait()ในแง่ของมนุษย์ อ้าง:

ในที่สุดทุกอย่างก็ลงไปถึงตัวกำหนดตารางเวลาของระบบปฏิบัติการซึ่งจะแจกแจงช่วงเวลาให้กับกระบวนการและเธรด

sleep(n)กล่าวว่า"ฉันทำกับไทม์สของฉันแล้วและโปรดอย่าให้อีกอย่างน้อย n มิลลิวินาที" ระบบปฏิบัติการไม่ได้พยายามกำหนดตารางเวลาการนอนจนกว่าจะถึงเวลาที่ร้องขอ

yield()พูดว่า"ฉันทำกับไทม์สของฉันเสร็จแล้ว แต่ฉันยังมีงานต้องทำ" ระบบปฏิบัติการมีอิสระที่จะให้เธรดอีกครั้งในทันทีหรือให้เธรดอื่นหรือประมวลผล CPU ที่เธรดผลผลิตยอมแพ้

wait()พูดว่า“ ฉันทำกับไทม์สของฉันเสร็จแล้ว อย่าให้เวลาฉันอีกเลยจนกว่าจะมีคนโทรมาแจ้ง ()” เช่นเดียวกับsleep()OS จะไม่พยายามกำหนดเวลางานของคุณจนกว่าจะมีคนโทรเข้าnotify()มา

เธรดยังสูญเสียช่วงเวลาที่เหลือของพวกเขาเมื่อพวกเขาทำการบล็อก IO และภายใต้สถานการณ์อื่น ๆ หากเธรดทำงานตลอดทั้งช่วงเวลาระบบปฏิบัติการบังคับใช้การควบคุมอย่างคร่าว ๆ ราวกับว่าyield()ถูกเรียกใช้เพื่อให้กระบวนการอื่นสามารถทำงานได้

คุณไม่ค่อยต้องการyield()แต่ถ้าคุณมีแอพคำนวณหนักที่มีขอบเขตงานแบบโลจิคัลการแทรก a yield() อาจปรับปรุงการตอบสนองของระบบ (เสียเวลา - การสลับบริบทแม้แต่กับระบบปฏิบัติการและด้านหลังเท่านั้น) วัดและทดสอบกับเป้าหมายที่คุณสนใจเช่นเคย


อัตราผลตอบแทนนั้นขึ้นอยู่กับแพลตฟอร์ม ... javamex.com/tutorials/threads/yield.shtml
Pacerier

คำอธิบายของsleep(n)ถูกโดยปริยายบอกว่าหัวข้อที่กำลังทำงานอยู่ relinquishes จอภาพล็อคโดยสมัครใจซึ่งเป็นไม่เป็นความจริง อ้างจากjavadoc ของ Thread : "เธรดไม่สูญเสียความเป็นเจ้าของจอภาพใด ๆ "
Clint Eastwood

2
@ Jonathan ไม่มีการกล่าวถึงจอภาพในคำตอบและนั่นเป็นเพราะsleepไม่มีพฤติกรรมพิเศษใด ๆ เกี่ยวกับการตรวจสอบมากกว่าการเรียกใช้เมธอด Java อื่น ๆ นั่นคือมันไม่ได้โต้ตอบหรือแก้ไขในทางใดทางหนึ่ง หากคุณจะพูดบางอย่างเกี่ยวกับจอภาพคุณควรระบุสิ่งwaitนั้นนอกเหนือจากสิ่งที่กล่าวไว้ข้างต้นปลดล็อควัตถุที่ถูกเรียกใช้ชั่วคราว
pqnet

การแจ้งเตือนทำงานอย่างไรในระดับกำหนดการของระบบปฏิบัติการ การแจ้งเตือนเรียกตัวจัดการเหตุการณ์บางประเภทที่มี id เธรดเฉพาะทำให้ตัวกำหนดตารางเวลาสามารถนำเธรดที่เกี่ยวข้องกลับมาในคิวที่รันอยู่ นอกจากนี้ฉันยังมีคำถามอื่นแนวคิดของ spinlock เหมาะสมกับอะไร? มันจะเกี่ยวข้องเฉพาะกับการนอนหลับหรือรอตัวเองใช้ spinlock ในระดับต่ำมาก?
CMCDragonkai

@Erich, ใช้เพื่อเปรียบเทียบกับwait(n) sleep(n)ไม่มีเหตุผลในการเปรียบเทียบการใช้ no-arg
Pacerier

68

มีคำตอบมากมายที่นี่ แต่ฉันไม่พบความแตกต่างทางความหมายที่กล่าวถึง

มันไม่เกี่ยวกับเธรดเอง จำเป็นต้องใช้ทั้งสองวิธีเนื่องจากจะรองรับกรณีการใช้งานที่แตกต่างกันมาก

sleep()ส่งเธรดเข้าสู่โหมดสลีปเหมือนก่อนหน้านี้เพียงแค่แพ็คบริบทและหยุดดำเนินการตามเวลาที่กำหนดไว้ล่วงหน้า ดังนั้นในการปลุกก่อนถึงกำหนดเวลาคุณต้องทราบการอ้างอิงของเธรด นี่ไม่ใช่สถานการณ์ทั่วไปในสภาพแวดล้อมแบบมัลติเธรด ส่วนใหญ่จะใช้สำหรับการซิงโครไนซ์เวลา (เช่นการปลุกในเวลา 3.5 วินาที) และ / หรือความเป็นธรรมแบบตายตัว (แค่หลับชั่วขณะหนึ่งและปล่อยให้เธรดอื่นทำงาน)

wait()ตรงกันข้ามคือกลไกการซิงโครไนซ์เธรด (หรือข้อความ) ที่ช่วยให้คุณสามารถแจ้งเธรดที่คุณไม่มีการอ้างอิงที่เก็บไว้ (หรือไม่สนใจ) คุณสามารถคิดว่ามันเป็นรูปแบบการประกาศสมัคร ( wait== สมัครและnotify()== เผยแพร่) โดยทั่วไปใช้การแจ้งเตือน () คุณกำลังส่งข้อความ (ซึ่งอาจไม่ได้รับเลยและโดยปกติคุณไม่สนใจ)

เพื่อสรุปผลโดยปกติคุณใช้sleep()สำหรับการwait()ซิงโครไนซ์เวลาและสำหรับการซิงโครไนซ์แบบหลายเธรด

พวกเขาสามารถนำไปใช้ในลักษณะเดียวกันในระบบปฏิบัติการพื้นฐานหรือไม่เลย (เนื่องจาก Java เวอร์ชันก่อนหน้านี้ไม่มีมัลติเธรดจริงจริงอาจเป็น VM ขนาดเล็กบางอย่างไม่ทำเช่นนั้น) อย่าลืม Java ที่รันบน VM ดังนั้นโค้ดของคุณจะถูกเปลี่ยนในสิ่งที่แตกต่างไปตาม VM / OS / HW ที่รันอยู่


54

ที่นี่ฉันได้แสดงความแตกต่างที่สำคัญบางอย่างระหว่างwait()และsleep()วิธีการ
PS: คลิกที่ลิงค์เพื่อดูรหัสห้องสมุด (การทำงานภายในเพียงเล่นไปรอบ ๆ เพื่อความเข้าใจที่ดีขึ้น)

รอ()

  1. wait() วิธีการปลดล็อค
  2. wait()เป็นวิธีการObjectเรียน
  3. wait() เป็นวิธีที่ไม่คงที่ - public final void wait() throws InterruptedException { //...}
  4. wait()ควรได้รับแจ้งโดยnotify()หรือnotifyAll()วิธีการ
  5. wait() วิธีการจะต้องมีการเรียกจากวงเพื่อจัดการกับการเตือนที่ผิดพลาด

  6. wait() ต้องเรียกใช้เมธอดจากบริบทที่ซิงโครไนซ์ (เช่นวิธีซิงโครไนซ์หรือบล็อก) มิฉะนั้นจะถูกโยน IllegalMonitorStateException

นอน()

  1. sleep() วิธีการไม่ได้ปลดล็อค
  2. sleep()เป็นวิธีการjava.lang.Threadเรียน
  3. sleep() เป็นวิธีการคงที่ - public static void sleep(long millis, int nanos) throws InterruptedException { //... }
  4. หลังจากระยะเวลาที่ระบุsleep()เสร็จสมบูรณ์
  5. sleep()ดีกว่าไม่โทรจากลูป (เช่นดูรหัสด้านล่าง )
  6. sleep()อาจถูกเรียกจากที่ใดก็ได้ ไม่มีข้อกำหนดเฉพาะ

Ref: ความแตกต่างระหว่าง Wait และ Sleep

ข้อมูลโค้ดสำหรับการโทรรอและวิธีการนอนหลับ

synchronized(monitor){
    while(condition == true){ 
        monitor.wait()  //releases monitor lock
    }

    Thread.sleep(100); //puts current thread on Sleep    
}

การเปลี่ยนเธรดเป็นสถานะเธรดที่แตกต่างกัน


มันถูกต้องหรือไม่ที่ด้ายการนอนหลับสามารถถูกปลุกด้วยการโทรเพื่อแจ้ง ()? โพสต์อื่น ๆ ที่นี่บางส่วนดูเหมือนจะบอกเป็นนัยว่าด้ายนอนไม่สามารถถูกปลุก แต่ถูกขัดจังหวะ
berimbolo

ใช่Thread.sleep()ใช้เพื่อทำให้เวลาตัวประมวลผลพร้อมใช้งานสำหรับเธรดอื่น ระยะเวลาสลีปสามารถยกเลิกได้โดยการขัดจังหวะ (เช่นโดย JVM) อ่านstackoverflow.com/questions/4264355/
roottraveller

โพสต์นั้นยังบอกว่าขัดจังหวะ () เป็นสิ่งที่ปลุกด้ายนอน? ฉันอ้างถึงไดอะแกรมสถานะเธรดที่คุณโพสต์ซึ่งมีข้อความแจ้งว่าแจ้งหรือแจ้งเตือนทั้งหมดนำเธรดที่กำลังหลับ (ไม่รอ) กลับมาให้พร้อมที่จะทำงาน ฉันแค่ต้องการให้แน่ใจว่าฉันเข้าใจ
berimbolo

@berimbolo notify()หรือnotifyAll()เป็นObjectวิธีการเรียน ดังนั้นพวกเขาจะพร้อมใช้งานจะ obj ของทุกชั้นเรียน (เช่นที่นี่กับThreadชั้นเรียนด้วย) ดูรหัสgrepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
roottraveller

2
ตกลงฉันต้องอ่านเพิ่มเติมเกี่ยวกับการตั้งเวลาของเธรดเนื่องจากฉันไม่สามารถหาตัวอย่างของแจ้ง () หรือ alertAll () ที่กำลังปลุกเธรดหลับเท่านั้นขัดจังหวะ () การทำเช่นนี้ ตัวอย่างทั้งหมดเกี่ยวข้องกับ alert () และ INFORMAll () กับเธรดที่กำลังรอบนวัตถุมอนิเตอร์บางตัว
berimbolo

29

มีข้อแตกต่างที่สำคัญที่ฉันสรุปหลังจากทำงานระหว่างรอและนอนหลับก่อนอื่นมาดูตัวอย่างโดยใช้ wait () และ sleep ():

ตัวอย่างที่ 1 : การใช้wait () และsleep ():

synchronized(HandObject) {
    while(isHandFree() == false) {
        /* Hand is still busy on happy coding or something else, please wait */
        HandObject.wait();
    }
}

/* Get lock ^^, It is my turn, take a cup beer now */
while (beerIsAvailable() == false) {
    /* Beer is still coming, not available, Hand still hold glass to get beer,
       don't release hand to perform other task */
    Thread.sleep(5000);
}

/* Enjoy my beer now ^^ */
drinkBeers();

/* I have drink enough, now hand can continue with other task: continue coding */
setHandFreeState(true);
synchronized(HandObject) {
    HandObject.notifyAll();
}

ให้ชัดเจนหมายเหตุสำคัญบางอย่าง:

  1. โทร :
    • wait (): เรียกใช้เธรดปัจจุบันที่ถือ HandObject Object
    • sleep (): Call on Thread execute task รับเบียร์ (เป็นวิธีการเรียนดังนั้นส่งผลต่อเธรดที่กำลังรันอยู่ปัจจุบัน)
  2. ทำข้อมูลให้ตรงกัน :
    • รอ (): เมื่อซิงโครไนซ์เข้าถึงหลายเธรดเข้าถึงวัตถุเดียวกัน (HandObject) (เมื่อต้องการการสื่อสารระหว่างมากกว่าหนึ่งเธรด (เธรดดำเนินการเข้ารหัส, เธรดเรียกใช้รับเบียร์) เข้าถึงวัตถุเดียวกัน HandObject)
    • sleep (): เมื่อเงื่อนไขการรอเพื่อดำเนินการต่อ (กำลังรอเบียร์)
  3. ล็อคค้างไว้ :
    • wait (): ปล่อยล็อคสำหรับวัตถุอื่นมีโอกาสที่จะดำเนินการ (HandObject ฟรีคุณสามารถทำงานอื่นได้)
    • sleep (): ล็อคอย่างน้อย t ครั้ง (หรือจนกว่าจะขัดจังหวะ) (งานของฉันยังไม่เสร็จสิ้นฉันยังคงล็อคและรอเงื่อนไขบางอย่างเพื่อดำเนินการต่อ)
  4. สภาพการตื่นนอน :
    • รอ (): จนกระทั่งการแจ้งเตือนการโทร (), alertAll () จากวัตถุ
    • sleep (): อย่างน้อยก็จนกว่าเวลาจะหมดลง
  5. และจุดสุดท้ายคือการใช้เมื่อเป็นestaniบ่งชี้:

โดยปกติคุณใช้ sleep () สำหรับการซิงโครไนซ์เวลาและรอ () สำหรับการซิงโครไนซ์แบบหลายเธรด

โปรดแก้ไขฉันหากฉันผิด


25

ความแตกต่างระหว่าง wait () และ sleep ()

  • ความแตกต่างพื้นฐานคือว่าwait()จากObjectและเป็นวิธีการที่คงที่ของsleep()Thread

  • ข้อแตกต่างที่สำคัญคือwait()การปลดล็อกขณะที่sleep()ไม่ปล่อยการล็อกขณะรอ

  • wait()ใช้สำหรับการสื่อสารระหว่างเธรดในขณะที่sleep()ใช้เพื่อแนะนำการหยุดชั่วคราวในการดำเนินการโดยทั่วไป

  • wait()ควรถูกเรียกจากภายในซิงโครไนซ์มิฉะนั้นเราจะได้รับIllegalMonitorStateExceptionในขณะที่sleep() สามารถเรียกได้จากทุกที่

  • ในการเริ่มต้นด้ายอีกครั้งจากwait()คุณต้องโทรหรือnotify() notifyAll()สำหรับsleep(),เธรดเริ่มต้นหลังจากช่วงเวลาที่ระบุ

ความคล้ายคลึงกัน

  • ทั้งสองให้ไปเธรดปัจจุบันลงในไม่ Runnableรัฐ
  • ทั้งสองเป็นวิธีการพื้นเมือง

18

นี่เป็นคำถามที่ง่ายมากเพราะทั้งสองวิธีนี้มีการใช้ที่แตกต่างกันโดยสิ้นเชิง

ข้อแตกต่างที่สำคัญคือการรอการปลดล็อคหรือจอภาพในขณะที่ sleep ไม่ได้ทำการปลดล็อคหรือมอนิเตอร์ใด ๆ ในขณะที่รอ รอใช้สำหรับการสื่อสารระหว่างเธรดในขณะที่ใช้โหมดสลีปเพื่อหยุดการทำงานชั่วคราว

นี่เป็นเพียงคำอธิบายที่ชัดเจนและพื้นฐานถ้าคุณต้องการมากกว่านั้นอ่านต่อ

ในกรณีที่wait()เมธอดเธรดอยู่ในสถานะรอและจะไม่กลับมาโดยอัตโนมัติจนกว่าเราจะเรียกnotify()เมธอด (หรือnotifyAll()ถ้าคุณมีมากกว่าหนึ่งเธรดในสถานะรอและคุณต้องการปลุกเธรดเหล่านั้นทั้งหมด) และคุณต้องซิงโครไนซ์หรือล็อควัตถุหรือล็อคคลาสเพื่อเข้าถึงwait()หรือnotify()หรือnotifyAll()วิธีการ และอีกสิ่งหนึ่งwait()วิธีนี้ใช้สำหรับการสื่อสารระหว่างเธรดเนื่องจากถ้าเธรดเข้าสู่สถานะรอคุณจะต้องใช้เธรดอื่นเพื่อปลุกเธรดนั้น

แต่ในกรณีsleep()นี้เป็นวิธีการที่ใช้ในการพักกระบวนการสักสองสามวินาทีหรือเวลาที่คุณต้องการ เพราะคุณไม่จำเป็นต้องยั่วยุใด ๆnotify()หรือnotifyAll()วิธีการเพื่อให้ได้ด้ายที่กลับมา หรือคุณไม่ต้องการเธรดอื่นเพื่อโทรกลับเธรดนั้น เช่นถ้าคุณต้องการบางสิ่งบางอย่างจะเกิดขึ้นหลังจากไม่กี่วินาทีเช่นในเกมหลังจากที่ผู้ใช้เปิดคุณต้องการให้ผู้ใช้รอจนกว่าคอมพิวเตอร์จะเล่นแล้วคุณสามารถพูดถึงsleep()วิธีการ

และอีกหนึ่งความแตกต่างที่สำคัญที่มักถูกถามบ่อยๆในการสัมภาษณ์: sleep()เป็นของThreadชั้นเรียนและwait()เป็นของObjectชั้น

เหล่านี้ล้วนเป็นความแตกต่างระหว่างและsleep()wait()

และมีความคล้ายคลึงกันระหว่างทั้งสองวิธี: พวกเขาทั้งคู่ได้รับการตรวจสอบคำสั่งดังนั้นคุณต้องลองจับหรือโยนเพื่อเข้าถึงวิธีการเหล่านี้

ฉันหวังว่านี่จะช่วยคุณได้


16

แหล่งที่มา: http://www.jguru.com/faq/view.jsp?EID=47127

Thread.sleep()ส่งเธรดปัจจุบันไปยังสถานะ"Not Runnable"เป็นระยะเวลาหนึ่ง เธรดจะเก็บมอนิเตอร์ที่ได้รับ - เช่นถ้าเธรดอยู่ในบล็อกที่ซิงโครไนซ์หรือวิธีการในปัจจุบันไม่มีเธรดอื่นใดที่สามารถเข้าสู่บล็อกหรือเมธอดนี้ได้ หากเธรดอื่นเรียกt.interrupt()มันจะทำให้เธรดนอนหลับตื่นขึ้นมา

โปรดทราบว่าการนอนหลับเป็นวิธีการคงที่ซึ่งหมายความว่ามันจะส่งผลกระทบต่อเธรดปัจจุบันเสมอ (หนึ่งที่กำลังดำเนินการวิธีการนอนหลับ) ข้อผิดพลาดทั่วไปคือโทรหาt.sleep()ที่ t เป็นเธรดอื่น แม้มันจะเป็นเธรดปัจจุบันที่จะนอนไม่ใช่เธรด t

t.suspend()เลิกใช้แล้ว การใช้เป็นไปได้ที่จะหยุดเธรดอื่นที่ไม่ใช่เธรดปัจจุบัน เธรดที่ถูกหยุดชั่วคราวทำให้จอภาพทั้งหมดและเนื่องจากสถานะนี้ไม่สามารถขัดจังหวะได้

object.wait()ส่งเธรดปัจจุบันไปยังสถานะ"Not Runnable"เช่นsleep()แต่มีการบิด การรอถูกเรียกบนวัตถุไม่ใช่เธรด เราเรียกวัตถุนี้ว่า "ล็อควัตถุ" ก่อนที่จะlock.wait()ถูกเรียกเธรดปัจจุบันต้องซิงโครไนซ์บนวัตถุล็อค wait() จากนั้นปล่อยการล็อกนี้และเพิ่มเธรดลงใน "รายการรอ" ที่เกี่ยวข้องกับการล็อก หลังจากนั้นเธรดอื่นสามารถซิงโครไนซ์กับวัตถุล็อคและการโทรlock.notify()เดียวกันได้ สิ่งนี้จะปลุกเธรดที่รออยู่เดิม โดยทั่วไปwait()/ notify()เป็นเหมือน sleep()/ interrupt()เฉพาะเธรดที่แอ็คทีฟไม่จำเป็นต้องมีตัวชี้โดยตรงไปยังเธรดที่กำลังหลับอยู่ แต่ใช้กับวัตถุล็อคที่ใช้ร่วมกันเท่านั้น


14

รอและนอนหลับเป็นสองสิ่งที่แตกต่าง:

  • ในsleep()เธรดหยุดทำงานตามระยะเวลาที่กำหนด
  • ในwait()เธรดหยุดทำงานจนกว่าวัตถุที่รออยู่จะได้รับแจ้งโดยทั่วไปโดยเธรดอื่น ๆ

แต่คุณสามารถขัดจังหวะการนอนหลับ ในกรณีที่การรอคอย () เป็น Infact ซ้ำซ้อนมันเสียรอบการทำงานมากเกินไป :-(
Geek

9
รอไม่ต้องเสียรอบ CPU
ปีเตอร์ibrtibraný

1
@ Peter - ฉันคิดว่ามันจะ มันรอ () สำหรับรอบของ CPU รอบและจากนั้นระบบปฏิบัติการให้รอบของ CPU ไปที่เธรดอื่น ๆ ฉันคิดว่านี่อาจจะขึ้นอยู่กับระบบปฏิบัติการฉันไม่แน่ใจ
Geek

3
มันจะใช้งานการรอ () ที่แย่มากถ้ามันทำให้ซีพียูเสียเปล่า การรอ / แจ้งใช้ค่อนข้างมากสำหรับการสื่อสารระหว่างกัน
ปีเตอร์ibrtibraný

2
@Pacerier โครงสร้างทั้งสองนี้มีจุดประสงค์เพื่อจุดประสงค์ที่แตกต่าง หากคุณต้องการด้ายที่จะหยุดสำหรับจำนวนเงินที่คงที่ของเวลาที่คุณใช้sleepถ้าคุณต้องการให้หยุดจนกว่าการป้อนข้อมูลบางส่วนมาจากที่อื่น ๆ ที่คุณใช้/wait มีจุดประสงค์เพื่อส่งสัญญาณเธรดที่ควรหยุดทำในสิ่งที่ทำและยุติ มันจะถูกจัดการโดย, แต่ยังปิดกั้นฟังก์ชัน I / O (และคุณสามารถใช้ฟังก์ชั่นที่มีพฤติกรรมเดียวกันโดยเรียกวิธีการ) สำหรับประสิทธิภาพนั้นมักมีการปรับฟังก์ชั่นการทำงานให้เหมาะกับเป้าหมายที่ออกแบบไว้ notifyinterruptsleepwaitThread.interrupted()
pqnet

11

sleepเป็นวิธีการThread, waitเป็นวิธีการObject, ดังนั้นwait/notifyเป็นเทคนิคการซิงโครไนซ์ข้อมูลที่ใช้ร่วมกันใน Java (ใช้มอนิเตอร์ ), แต่sleepเป็นวิธีการง่าย ๆ ของเธรดเพื่อหยุดตัวเอง


8

sleep ()เป็นวิธีการที่ใช้ในการเก็บกระบวนการไม่กี่วินาทีหรือเวลาที่คุณต้องการ แต่ในกรณีของการรอ () วิธีการด้ายไปในสถานะรอและมันจะไม่กลับมาโดยอัตโนมัติจนกว่าเราจะเรียกการแจ้งเตือน () หรือ notifyAll ()

ข้อแตกต่างที่สำคัญคือการรอ ()ปล่อยการล็อกหรือมอนิเตอร์ในขณะที่ sleep () ไม่ปล่อยการล็อกหรือจอภาพใด ๆ ในขณะที่รอ รอใช้สำหรับการสื่อสารระหว่างเธรดในขณะที่โหมดสลีปใช้เพื่อแนะนำการหยุดชั่วขณะโดยทั่วไป

Thread.sleep ()ส่งเธรดปัจจุบันไปยังสถานะ“ Not Runnable” เป็นระยะเวลาหนึ่ง เธรดจะเก็บมอนิเตอร์ที่ได้มานั่นคือถ้าเธรดอยู่ในบล็อกที่ซิงโครไนซ์หรือวิธีการในปัจจุบันไม่มีเธรดอื่นใดที่สามารถเข้าสู่บล็อกหรือเมธอดนี้ได้ หากเธรดอื่นเรียก t.interrupt () เธรดนั้นจะปลุกเธรดที่กำลังหลับอยู่ โปรดทราบว่าการนอนหลับเป็นวิธีการคงที่ซึ่งหมายความว่ามันจะส่งผลกระทบต่อเธรดปัจจุบันเสมอ (หนึ่งที่กำลังดำเนินการวิธีการนอนหลับ) ข้อผิดพลาดทั่วไปคือโทร t.sleep () โดยที่ t เป็นเธรดอื่น แม้มันจะเป็นเธรดปัจจุบันที่จะนอนไม่ใช่เธรด t

object.wait ()ส่งเธรดปัจจุบันไปยังสถานะ“ Not Runnable” เช่น sleep () แต่มีการบิด การรอถูกเรียกบนวัตถุไม่ใช่เธรด เราเรียกวัตถุนี้ว่า "ล็อควัตถุ" ก่อนที่จะเรียกใช้ lock.wait () เธรดปัจจุบันจะต้องซิงโครไนซ์กับวัตถุล็อค รอ () จากนั้นปล่อยการล็อกนี้และเพิ่มเธรดใน“ รายการรอ” ที่เกี่ยวข้องกับการล็อค หลังจากนั้นเธรดอื่นสามารถซิงโครไนซ์กับวัตถุล็อคเดียวกันและโทร lock.notify () สิ่งนี้จะปลุกเธรดที่รออยู่เดิม โดยทั่วไปแล้วรอ () / แจ้งเตือน () เป็นเหมือน sleep () / ขัดจังหวะ () เฉพาะเธรดที่ใช้งานอยู่ไม่จำเป็นต้องมีตัวชี้โดยตรงไปยังกระทู้นอน แต่เพียงวัตถุล็อคที่ใช้ร่วมกัน

synchronized(LOCK) {   
   Thread.sleep(1000); // LOCK is held
}

synchronized(LOCK) {   
   LOCK.wait(); // LOCK is not held
}

ให้จัดหมวดหมู่คะแนนทั้งหมดข้างต้น:

Call on:

  • wait ():โทรหาวัตถุ; เธรดปัจจุบันต้องซิงโครไนซ์กับวัตถุล็อค
  • sleep ():โทรหาเธรด กำลังรันเธรดอยู่เสมอ

Synchronized:

  • wait ():เมื่อซิงโครไนซ์หลายเธรดเข้าถึง Object เดียวกันทีละรายการ
  • sleep ():เมื่อซิงโครไนซ์หลายเธรดรอให้สลีปของเธรดการนอนหลับตรงกัน

Hold lock:

  • wait ():ปลดล็อกเพื่อให้อ็อบเจกต์อื่นมีโอกาสที่จะดำเนินการ
  • sleep ():ล็อคอย่างน้อย t ครั้งหากมีการระบุการหมดเวลาหรือมีคนขัดจังหวะ

Wake-up condition:

  • รอ ():จนกระทั่งการแจ้งเตือนการโทร (), alertAll () จากวัตถุ
  • sleep ():จนกระทั่งอย่างน้อยเวลาหมดอายุหรือ call interrupt ()

Usage:

  • sleep ():สำหรับการซิงโครไนซ์เวลาและ;
  • wait ():สำหรับการทำข้อมูลให้ตรงกันหลายเธรด

Ref: diff sleepและwait


6

กล่าวง่ายๆคือรอคือรอจนกว่าเธรดอื่น ๆ จะเรียกคุณขณะที่โหมดสลีปคือ "ไม่เรียกใช้คำสั่งถัดไป" สำหรับช่วงเวลาที่ระบุ

ยิ่งไปกว่านั้น sleep เป็นสแตติกเมธอดในคลาส Thread และทำงานบน thread ในขณะที่ wait () อยู่ในคลาส Object และเรียกใช้บนอ็อบเจ็กต์

อีกจุดหนึ่งเมื่อคุณเรียกใช้รอวัตถุบางอย่างเธรดที่เกี่ยวข้องประสานวัตถุแล้วรอ :)


1
ทำไมคุณถึงต้องการทั้งสองอย่าง? ทำไมการนอนหลับ () ไม่เพียงพอ?
Geek

2
การแจ้งเตือนใช้สำหรับการสื่อสารระหว่างเธรด ในการรับสายคุณต้องมีวัตถุบางอย่างซิงโครไนซ์แล้วจึงรอสาย หากต้องการรับการแจ้งเตือนคุณต้องมีเธรดอื่นเพื่อซิงโครไนซ์บนวัตถุเดียวกันและโทรแจ้งเตือน
ปีเตอร์ibrtibraný

6

waitและsleepวิธีการต่างกันมาก:

  • sleep ไม่มีทางที่จะ "ตื่นขึ้น"
  • ในขณะที่waitมีวิธีการ "ตื่นขึ้น" ในช่วงระยะเวลาการรอคอยโดยโทรหัวข้ออื่นหรือnotifynotifyAll

ลองคิดดูสิชื่อนั้นสร้างความสับสนในแง่นั้น อย่างไรก็ตามsleepเป็นชื่อมาตรฐานและwaitเหมือนกับWaitForSingleObjectหรือWaitForMultipleObjectsใน Win API


3
แต่เราสามารถขัดจังหวะการนอนไม่ได้ใช่ไหม ดังนั้นความแตกต่างของการนอนหลับ / การขัดจังหวะเมื่อเทียบกับการรอ / แจ้งเตือนคืออะไร
Pacerier

2
คุณสามารถขัดจังหวะการนอนหลับ แต่คุณสามารถแจ้งเตือนผู้รอเท่านั้น หัวข้อเหมือนกัน
Rishi

5

จากโพสต์นี้: http://javaconceptoftheday.com/difference-between-wait-and-sleep-methods-in-java/

วิธีการรอ ()

1) เธรดที่เรียกใช้ wait () วิธีการปลดล็อคมันถือ

2) เธรดจะล็อกอีกครั้งหลังจากที่เธรดอื่นเรียกเมธอดแจ้งเตือน () หรือ alertAll () ทั้งหมดในการล็อกเดียวกัน

3) ต้องรอเมธอด () ภายในบล็อกที่ซิงโครไนซ์

4) การรอ () วิธีการมักจะเรียกว่าบนวัตถุ

5) การรอเธรดสามารถปลุกโดยเธรดอื่น ๆ ได้โดยการเรียกการแจ้งเตือน () หรือวิธีแจ้งเตือนทั้งหมด

6) เมธอด call wait () วิธีการ thread ต้องมีการล็อควัตถุ

วิธีการนอนหลับ ()

1) เธรดที่เรียกใช้โหมดสลีป () ไม่ได้ปลดล็อคที่เก็บไว้

2) วิธีการ sleep () สามารถเรียกได้ทั้งภายในหรือภายนอกบล็อกที่ซิงโครไนซ์

3) การนอนหลับ () วิธีการที่มักจะเรียกว่าหัวข้อ

4) หัวข้อการนอนหลับไม่สามารถปลุกโดยกระทู้อื่น ๆ ได้ หากทำเช่นนั้นด้ายจะโยน InterruptedException

5) วิธีการโทร sleep () วิธีการเธรดไม่จำเป็นต้องล็อควัตถุ


4

รอที่นี่ () จะอยู่ในสถานะรอจนกว่าจะได้รับแจ้งจากเธรดอื่น แต่ในกรณีที่ sleep () จะมีเวลาสักครู่ .. หลังจากนั้นมันจะโอนไปยังสถานะพร้อมโดยอัตโนมัติ ...


4
  1. wait()เป็นวิธีการObjectเรียน
    sleep()เป็นวิธีการThreadเรียน

  2. sleep()อนุญาตให้เธรดไปยังsleepสถานะสำหรับ x มิลลิวินาที
    เมื่อเธรดเข้าสู่สถานะit doesn’t release the lockสลีป

  3. wait()goes to suspended stateช่วยให้ด้ายที่จะปล่อยล็อคและ
    เธรดนี้จะใช้งานได้เมื่อมีการเรียกวิธีการnotify()หรือnotifAll()สำหรับวัตถุเดียวกัน


4

ความแตกต่างที่สำคัญอย่างหนึ่งระหว่างการนอนหลับ / การขัดจังหวะและการรอ / แจ้งคือ

การสร้างข้อยกเว้นเมื่อไม่ต้องการไม่มีประสิทธิภาพ หากคุณมีเธรดที่สื่อสารกันด้วยอัตราที่สูงมันจะสร้างข้อยกเว้นมากมายหากคุณโทรไปขัดจังหวะตลอดเวลาซึ่งเป็น CPU ที่เสียทั้งหมด


+1, จุดที่ถูกต้องจริงแม้ว่าการโต้เถียงในinternalsของการใช้งานอาจมีความเกี่ยวข้องกับการวิเคราะห์ประสิทธิภาพ ...
Pacerier

ในคำอื่น ๆ ค่าใช้จ่ายในการสร้างข้อยกเว้นอาจมีขนาดเล็กกว่าค่าใช้จ่ายอย่างมีนัยสำคัญของการใช้งานของระบบหนึ่งเทียบกับอื่น ๆ
Pacerier

3

คุณถูกต้อง - สลีป () ทำให้เธรดนั้น "สลีป" และ CPU จะดับและประมวลผลเธรดอื่น (หรือที่รู้จักกันในชื่อการสลับบริบท) ในขณะที่ฉันเชื่อว่า Wait จะคอยให้ CPU ประมวลผลเธรดปัจจุบัน

เรามีทั้งคู่เพราะแม้ว่ามันอาจดูสมเหตุสมผลที่จะให้คนอื่นใช้ CPU ในขณะที่คุณไม่ได้ใช้งาน แต่จริงๆแล้วมันมีค่าใช้จ่ายในการสลับบริบท - ขึ้นอยู่กับว่าสลีปนั้นใช้เวลานานแค่ไหน เพื่อสลับเธรดมากกว่าที่จะให้เธรดของคุณไม่ทำอะไรเลยสักสองสามมิลลิวินาที

นอกจากนี้โปรดทราบว่าโหมดสลีปจะบังคับให้สลับบริบท

นอกจากนี้ - โดยทั่วไปแล้วมันเป็นไปไม่ได้ที่จะควบคุมการสลับบริบท - ระหว่างรอระบบปฏิบัติการอาจ (และจะรออีกต่อไป) เลือกที่จะประมวลผลเธรดอื่น ๆ


4
wait () ไม่ให้ CPU ประมวลผลเธรดปัจจุบัน มันก็เหมือนการนอนหลับในการที่จะทำให้เกิดการเปลี่ยนบริบทเช่นกัน: javamex.com/tutorials/threads/context_switch.shtml ฉันขอครึ่งปีเกี่ยวกับ stackoverflow และดูเหมือนว่าไม่มีใครรู้ว่าอะไรคือความแตกต่างระหว่างการรอ / แจ้งเตือนเทียบกับการนอนหลับ / การขัดจังหวะ
Pacerier

แม้ว่า sleep จะไม่ทำให้ CPU ประมวลผลเธรดปัจจุบัน แต่ฉันคิดว่ามันเป็นภาระของ CPU อยู่เล็กน้อยเพราะ CPU ต้องการติดตามช่วงเวลาที่จะหยุดพัก ไม่มีทริกเกอร์ภายนอกเช่น "แจ้งเตือน" ในระหว่างรอ ไม่มี?
Vladimir Nabokov

@VladimirNabokov, interruptทริกเกอร์ภายนอก เวลาสิ้นสุดคือในn wait(n)¶¶เมื่อ 8 ปีที่แล้วและยังไม่มีใครได้รับคำตอบ!
Pacerier

3

วิธีการที่ใช้สำหรับสิ่งต่าง ๆ

Thread.sleep(5000);   // Wait until the time has passed.

Object.wait();        // Wait until some other thread tells me to wake up.

Thread.sleep (n) สามารถถูกขัดจังหวะได้ แต่ต้องแจ้งObject.wait () เป็นไปได้ที่จะระบุเวลาสูงสุดในการรอ: Object.wait(5000)ดังนั้นจึงเป็นไปได้ที่จะใช้wait, เอ่อsleepแต่คุณต้องกังวลกับการล็อค

ไม่มีวิธีใดใช้ cpu ในขณะที่หลับ / รอ

วิธีการที่จะดำเนินการโดยใช้รหัสพื้นเมืองโดยใช้โครงสร้างที่คล้ายกัน แต่ไม่ได้ในทางเดียวกัน

มองหาตัวเอง: มีซอร์สโค้ดของวิธีการเนทิฟหรือไม่ ไฟล์/src/share/vm/prims/jvm.cppนี้เป็นจุดเริ่มต้น ...


Thread.sleep timing สามารถตั้งค่าไม่ จำกัด เวลา Object.wait ยังสามารถตั้งค่าให้แน่นอน คำตอบนี้ไม่ได้อธิบายว่าทำไมเราถึงต้องการ 2 ค้อนที่ทำสิ่งเดียวกัน
Pacerier

Thread.sleep(big_num) จะต้องถูกขัดจังหวะ Object.wait(small_num) สามารถรับการแจ้งเตือน
Pacerier

3

รอ () และนอน () ความแตกต่าง?

Thread.sleep () เมื่องานเสร็จแล้วปล่อยเฉพาะล็อคให้ทุกคน จนกว่าจะไม่ปล่อยล็อคให้ใคร

  Sleep() take the key, its never release the key to anyone, when its work completed then only its release then only take the key waiting stage threads.

Object.wait () เมื่อมันกำลังจะอยู่ในช่วงรอมันจะถูกปล่อยคีย์และมันกำลังรอบางวินาทีตามพารามิเตอร์

ตัวอย่างเช่น:

คุณกำลังหยิบกาแฟในมือขวาคุณสามารถหยิบมือเดียวกันกับใครก็ได้เมื่อคุณวางมือลงแล้วหยิบวัตถุชนิดเดียวกันอีกที่นี่ ด้วย นี่คือการนอนหลับ () คุณเวลานอนคุณไม่ได้ทำงานอะไรเลยคุณกำลังนอนเท่านั้น .. เหมือนกันที่นี่

รอ(). เมื่อคุณถูกวางลงและใช้อีกหนึ่งค่าเฉลี่ยในขณะที่คุณกำลังรอนั่นคือรอ

คุณกำลังเล่นภาพยนตร์หรืออะไรก็ตามในระบบของคุณเช่นเดียวกับผู้เล่นที่คุณไม่สามารถเล่นได้มากกว่าหนึ่งครั้งนั่นคือที่นี่เมื่อคุณปิดและเลือกภาพยนตร์หรือเพลงอื่น ๆ ในขณะที่เรียกว่ารอ


3

waitปลดล็อคและsleepไม่ทำ ด้ายในการรอคอยของรัฐมีสิทธิได้ตื่นขึ้นมาโดยเร็วnotifyหรือnotifyAllจะเรียกว่า แต่ในกรณีsleepที่เธรดยังคงล็อคอยู่และจะมีสิทธิ์ก็ต่อเมื่อเวลาสลีปสิ้นสุด


ดังนั้นหากเธรดนอนหลับเป็นเวลา 10 วินาทีและมีข้อยกเว้นขัดจังหวะเกิดขึ้น ????
Geek

@Geek An InterruptedExceptionถูกส่งออกไปดังที่ได้กล่าวไว้ใน Javadoc
user207421

@EJP: คุณเป็น EJP คนเดียวกับที่อยู่ในฟอรัม sun.java.com หรือไม่ Atleast คะแนนของคุณแนะนำ :-) เดียวกัน
Geek

2

sleep()เมธอดทำให้เธรดปัจจุบันย้ายจากสถานะการทำงานไปยังสถานะบล็อกสำหรับเวลาที่ระบุ ถ้าเธรดปัจจุบันมีการล็อกของวัตถุใด ๆ มันจะเก็บมันไว้ซึ่งหมายความว่าเธรดอื่นไม่สามารถดำเนินการวิธีการซิงโครไนซ์ใด ๆ ในวัตถุคลาสนั้น

wait() เมธอดทำให้เธรดปัจจุบันเข้าสู่สถานะบล็อกอย่างใดอย่างหนึ่งตามเวลาที่กำหนดหรือจนกว่าจะแจ้งเตือน แต่ในกรณีนี้เธรดจะปลดล็อกของวัตถุ (ซึ่งหมายความว่าเธรดอื่นสามารถดำเนินการวิธีการซิงโครไนซ์ใด ๆ


2

ในความคิดของฉันความแตกต่างที่สำคัญระหว่างกลไกทั้งสองคือการนอนหลับ / ขัดจังหวะเป็นวิธีพื้นฐานที่สุดในการจัดการเธรดในขณะที่การรอ / แจ้งเตือนเป็นสิ่งที่เป็นนามธรรม ซึ่งหมายความว่าการนอนหลับ / การขัดจังหวะสามารถทำอะไรก็ได้ แต่งานที่เฉพาะเจาะจงนี้ทำได้ยากกว่า

เหตุใดการรอ / แจ้งจึงเหมาะสมกว่า นี่คือข้อควรพิจารณาส่วนตัวบางประการ:

  1. มันบังคับใช้การรวมศูนย์ จะช่วยให้ประสานงานการสื่อสารระหว่างกลุ่มของกระทู้กับวัตถุที่ใช้ร่วมกันเดียว ทำให้การทำงานง่ายขึ้นมาก

  2. มันบังคับใช้การซิงโครไนซ์ เพราะมันทำให้โปรแกรมเมอร์ตัดสายเพื่อรอ / แจ้งในบล็อกที่ซิงโครไนซ์

  3. มันไม่ขึ้นอยู่กับที่มาและจำนวนของเธรด ด้วยวิธีนี้คุณสามารถเพิ่มเธรดเพิ่มเติมได้เองโดยไม่ต้องแก้ไขเธรดอื่น ๆ หรือติดตามแทร็กที่มีอยู่ หากคุณใช้การนอนหลับ / การขัดจังหวะก่อนอื่นคุณจะต้องเก็บการอ้างอิงไปยังเธรดการนอนหลับและจากนั้นขัดจังหวะพวกเขาทีละคนด้วยมือ

ตัวอย่างจากชีวิตจริงที่ดีที่จะอธิบายนี่เป็นร้านอาหารคลาสสิกและวิธีการที่พนักงานใช้ในการสื่อสารระหว่างพวกเขา: บริกรออกจากคำขอของลูกค้าในสถานที่กลาง (กระดานไม้ก๊อกโต๊ะ ฯลฯ ), กริ่งและคนงานจากครัวมารับคำร้อง เมื่อมีหลักสูตรพร้อมพนักงานครัวจะส่งเสียงระฆังอีกครั้งเพื่อให้พนักงานเสิร์ฟทราบและนำพวกเขาไปยังลูกค้า


2

ตัวอย่างเกี่ยวกับการนอนไม่ปลดล็อคและรอทำ

ที่นี่มีสองคลาส:

  1. หลัก : มีวิธีการหลักและสองหัวข้อ
  2. Singleton : นี่คือคลาสเดี่ยวที่มีสองวิธีคงที่ getInstance () และ getInstance (บูลีน isWait)

    public class Main {
    
    private static Singleton singletonA = null;
    private static Singleton singletonB = null;
    
    public static void main(String[] args) throws InterruptedException {
    
    Thread threadA = new Thread() {
        @Override
        public void run() {
    
            singletonA = Singleton.getInstance(true);
    
        }
    };
    
    Thread threadB = new Thread() {
        @Override
        public void run() {
            singletonB = Singleton.getInstance();
    
            while (singletonA == null) {
                System.out.println("SingletonA still null");
            }
    
            if (singletonA == singletonB) {
                System.out.println("Both singleton are same");
            } else {
                System.out.println("Both singleton are not same");
            }
    
        }
    };
    
    threadA.start();
    threadB.start();
    
     }
    }

และ

public class Singleton {

    private static Singleton _instance;

    public static Singleton getInstance() {

    if (_instance == null) {
        synchronized (Singleton.class) {
            if (_instance == null)
                _instance = new Singleton();
        }
    }
    return _instance;

}

public static Singleton getInstance(boolean isWait) {

    if (_instance == null) {
        synchronized (Singleton.class) {
            if (_instance == null) {
                if (isWait) {
                    try {
                        // Singleton.class.wait(500);//Using wait
                        Thread.sleep(500);// Using Sleep
                        System.out.println("_instance :"
                                + String.valueOf(_instance));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                _instance = new Singleton();
            }
        }
    }
    return _instance;

 }
}

ตอนนี้เรียกใช้ตัวอย่างนี้คุณจะได้รับผลลัพธ์ด้านล่าง:

_instance :null
Both singleton are same

อินสแตนซ์ของ Singleton ที่สร้างโดย threadA และ threadB เหมือนกัน มันหมายความว่า threadB กำลังรออยู่ข้างนอกจนกว่า threadA จะปลดล็อค

ตอนนี้เปลี่ยน Singleton.java โดยแสดงความคิดเห็น Thread.sleep (500); วิธีและ uncommenting Singleton.class.wait (500); . ที่นี่เพราะ Singleton.class.wait (500); เมธอด threadA จะปล่อยการล็อกทั้งหมดที่ได้รับและย้ายไปอยู่ในสถานะ“ ไม่สามารถรันได้” threadB จะได้รับการเปลี่ยนแปลงเพื่อป้อนในบล็อกที่ซิงโครไนซ์

ตอนนี้ทำงานอีกครั้ง:

SingletonA still null
SingletonA still null
SingletonA still null
_instance :com.omt.sleepwait.Singleton@10c042ab
SingletonA still null
SingletonA still null
SingletonA still null
Both singleton are not same

อินสแตนซ์ของ Singleton ที่สร้างโดย threadA และ threadB นี้ไม่เหมือนกันเนื่องจาก threadB มีการเปลี่ยนแปลงเพื่อป้อนในบล็อกที่ซิงโครไนซ์และหลังจาก 500 มิลลิวินาที threadA เริ่มต้นจากตำแหน่งสุดท้ายและสร้างวัตถุ Singleton อีกหนึ่งรายการ


2

ควรเรียกจากการซิงโครไนซ์บล็อก: wait()เมธอดจะถูกเรียกจากซิงโครไนซ์บล็อกเสมอเช่นwait()วิธีการจำเป็นต้องล็อคการตรวจสอบวัตถุก่อนวัตถุที่ถูกเรียก แต่sleep()สามารถเรียกใช้เมธอดจากบล็อกที่ซิงโครไนซ์ภายนอกเช่นsleep()เมธอดไม่ต้องการการตรวจสอบวัตถุใด ๆ

IllegalMonitorStateException:ถ้าwait()วิธีการที่ถูกเรียกโดยไม่ได้รับการล็อควัตถุกว่าIllegalMonitorStateExceptionจะถูกโยนที่รันไทม์ แต่sleep()วิธีการไม่เคยโยนข้อยกเว้นดังกล่าว

เป็นของ class: wait() method เป็นของjava.lang.Objectclass แต่sleep()method เป็นของjava.lang.Threadclass

เรียกใช้บนวัตถุหรือเธรด: wait()เมธอดถูกเรียกบนวัตถุ แต่sleep()มีการเรียกเมธอดบนเธรดไม่ใช่วัตถุ

สถานะของเธรด:เมื่อwait()มีการเรียกใช้เมธอดบนวัตถุเธรดที่มอนิเตอร์ของวัตถุที่ค้างไว้จะไม่สามารถเรียกใช้ไปยังสถานะที่รออยู่และสามารถกลับสู่สถานะที่ทำงานได้เฉพาะเมื่อมีการเรียกใช้เมธอดnotify()หรือnotifyAll()บนวัตถุนั้น และภายหลังกำหนดการตารางเวลาเธรดที่หัวข้อที่จะไปจาก runnable เพื่อสถานะการทำงาน เมื่อsleep()ถูกเรียกบนเธรดมันจะเริ่มจากการรันไปยังสถานะรอและสามารถกลับสู่สถานะที่รันได้เมื่อเวลาสลีปหมด

เมื่อเรียกจากซิงโครไนซ์บล็อก:เมื่อwait()เมธอดถูกเรียกว่าเธรดปล่อยให้ล็อกวัตถุ แต่sleep()วิธีการเมื่อเรียกจากซิงโครไนซ์บล็อกหรือเธรดเมธอดไม่ปล่อยให้ล็อกวัตถุ

สำหรับการอ้างอิงเพิ่มเติม


อาจเป็น URL อ้างอิงที่ดีกว่า URL นั้น
ดึง

2

จากหน้าเอกสาร Oracle ในวิธีการรอ ()ของObject:

public final void wait()
  1. ทำให้เธรดปัจจุบันรอจนกว่าเธรดอื่นจะเรียกnotify()เมธอดหรือnotifyAll()เมธอดสำหรับวัตถุนี้ ในคำอื่น ๆ wait(0)วิธีนี้จะทำงานตรงตามที่ถ้ามันก็จะดำเนินการเรียกร้อง
  2. เธรดปัจจุบันต้องเป็นเจ้าของจอภาพของวัตถุนี้ เธรดจะปล่อยความเป็นเจ้าของของจอภาพนี้และรอจนกว่าเธรดอื่นจะแจ้งให้เธรดที่รอบนจอภาพของวัตถุนี้ตื่นขึ้น
  3. การขัดจังหวะและการปลุกซ้ำที่เป็นไปได้
  4. วิธีการนี้ควรถูกเรียกโดยเธรดที่เป็นเจ้าของจอภาพของวัตถุนี้เท่านั้น

วิธีนี้จะพ่น

  1. IllegalMonitorStateException - หากเธรดปัจจุบันไม่ใช่เจ้าของจอภาพของวัตถุ

  2. InterruptedException- หากเธรดใด ๆ ขัดจังหวะเธรดปัจจุบันก่อนหรือขณะที่เธรดปัจจุบันกำลังรอการแจ้งเตือน สถานะที่ถูกขัดจังหวะของเธรดปัจจุบันจะถูกล้างเมื่อมีการโยนข้อยกเว้นนี้

จากหน้าเอกสาร oracle ในโหมด sleep ()ของThreadคลาส:

public static void sleep(long millis)
  1. ทำให้เธรดที่กำลังเรียกใช้งานอยู่ในขณะหลับ (หยุดการประมวลผลชั่วคราว) สำหรับจำนวนมิลลิวินาทีที่ระบุขึ้นอยู่กับความแม่นยำและความแม่นยำของตัวจับเวลาระบบและตัวกำหนดตารางเวลา
  2. เธรดไม่สูญเสียความเป็นเจ้าของจอภาพใด ๆ

วิธีนี้จะพ่น:

  1. IllegalArgumentException - ถ้าค่าของมิลลิวินาทีเป็นลบ

  2. InterruptedException- หากเธรดใด ๆ ขัดจังหวะเธรดปัจจุบัน สถานะที่ถูกขัดจังหวะของเธรดปัจจุบันจะถูกล้างเมื่อมีการโยนข้อยกเว้นนี้

ความแตกต่างที่สำคัญอื่น ๆ :

wait()เป็นวิธีที่ไม่คงที่ (วิธีการอินสแตนซ์) ซึ่งแตกต่างจากวิธีการคงที่sleep()(วิธีการเรียน)


1

wait()จะได้รับภายในวิธีการทำข้อมูลให้ตรงกันในขณะที่sleep()จะได้รับภายในวิธีการที่ไม่ตรงกันเพราะwait()วิธีการปลดล็อคบนวัตถุ แต่sleep()หรือไม่ปล่อยyield()lock()


sleep()สามารถอยู่ในsynchronizedบล็อกหรือวิธีการ คำตอบไม่ได้อธิบายอะไรเลย
user207421

1
  • วิธีการที่wait(1000)ทำให้เกิดเธรดปัจจุบันจะนอนหลับได้ถึงหนึ่งวินาที
    • เธรดอาจนอนหลับน้อยกว่า 1 วินาทีหากได้รับการเรียกnotify()หรือnotifyAll()เมธอด
  • เรียกร้องให้sleep(1000)สาเหตุเธรดปัจจุบันการนอนหลับว่า 1 วินาที
    • นอกจากนี้ยังมีหัวข้อการนอนหลับไม่ได้ถือล็อคทรัพยากรใดแต่ด้ายรอไม่

1
sleep(1000)ไม่รับประกันว่าจะนอนหลับเป็นเวลา 1 วินาที มันอาจจะถูกขัดจังหวะก่อน
Lucio

1
โพสต์เหล่านี้สับสนมาก โพสต์อื่น ๆ ทั้งหมดในกระทู้นี้บอกว่าด้ายนอนไม่ถือล็อคและว่าด้ายรอไม่ล็อคถือ ในทำนองเดียวกันการโพสต์กับไดอะแกรมหมายความว่าการเรียกเพื่อแจ้งเตือน () ปลุกเธรดที่กำลังหลับอยู่ แต่การโพสต์อื่น ๆ (และไดอะแกรมสถานะเธรด) บ่งบอกว่ามีเพียงการขัดจังหวะ () หรือรอบระยะเวลาการหมดเวลา ฉันเพิ่งสั่งสำเนาของ java concurrency ในทางปฏิบัติด้วยตัวเองสิ่งที่ฉันควรอ่านเมื่อนานมาแล้ว!
berimbolo

1

ที่จริงแล้วทั้งหมดนี้มีการอธิบายอย่างชัดเจนในเอกสาร Java (แต่ฉันรู้ว่านี้หลังจากอ่านคำตอบ)

http://docs.oracle.com/javase/8/docs/api/index.html :

wait () - เธรดปัจจุบันต้องเป็นเจ้าของจอภาพของวัตถุนี้ เธรดจะเผยแพร่ความเป็นเจ้าของของจอภาพนี้และรอจนกว่าเธรดอื่นจะแจ้งให้ทราบถึงเธรดที่รอบนจอภาพของวัตถุนี้เพื่อให้ตื่นขึ้นผ่านการเรียกใช้วิธีการแจ้งเตือนหรือเมธอดAllAll จากนั้นเธรดจะรอจนกว่าจะสามารถขอรับความเป็นเจ้าของจอภาพอีกครั้งและดำเนินการต่อ

sleep () - ทำให้เธรดที่กำลังรันอยู่ในปัจจุบันเข้าสู่โหมดสลีป (หยุดการประมวลผลชั่วคราว) สำหรับจำนวนมิลลิวินาทีที่ระบุขึ้นอยู่กับความแม่นยำและความแม่นยำของตัวจับเวลาระบบและตัวกำหนดตารางเวลา เธรดไม่สูญเสียความเป็นเจ้าของจอภาพใด ๆ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.