生活随笔
收集整理的這篇文章主要介紹了
多线程的通知机制
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
典型應用場景–阻塞隊列
生產者(Productor)—放入元素 消費者(Consumer)—取出元素 生產者放元素時,隊列滿了,該怎么辦? 消費者取元素時,隊列空了,該怎么辦? 沒有采用阻塞隊列之前采用一種輪詢模式 ,定期去問(性能浪費。實時性低)。 因此出現了另一種模式,通知模式 ,留個聯系方式,狀態改變以后會有人找你。
java中如何提供通知模式的?
Object的三個普通方法: wait();導致當前線程等待,直到另一個線程調用該對象的 notify()方法或 notifyAll()方法。 notify();喚醒正在等待對象監視器的單個線程。 notifyAll();喚醒正在等待對象監視器的所有線程。
由于Obejct是java中所有類的祖先類,所以,所有類的對象,都具備這三個方法。
注意事項:
要在某個對象(o)上進行wait/notify/notifyAll,首先必須持有這個對象的鎖
import java. util. concurrent. TimeUnit ; class MyThread extends Thread { @Override public void run ( ) { try { TimeUnit . SECONDS
. sleep ( 5 ) ; } catch ( InterruptedException e
) { e
. printStackTrace ( ) ; } synchronized ( ThreadDemo . o
) { ThreadDemo . o
. notify ( ) ; } }
}
public class ThreadDemo { static Object o
= new Object ( ) ; public static void main ( String [ ] args
) throws InterruptedException { MyThread thread
= new MyThread ( ) ; thread
. start ( ) ; System . out
. println ( "準備開始wait" ) ; synchronized ( o
) { o
. wait ( ) ; } System . out
. println ( "從wait中醒來" ) ; }
}
先notify再wait可以收到之前的通知信號嗎? 無法收到,通知信號狀態不保留。 在調用wait的線程真正放棄CPU之前隱含著一次釋放鎖的過程,釋放o這個鎖,而不是所有的鎖。 從wait返回之前,隱含著需要重新請求鎖(o這個鎖)。
package 阻塞隊列
. demo2
;
import java. util. * ;
public class ThreadDemo { public static void main ( String [ ] args
) throws InterruptedException { Scanner s
= new Scanner ( System . in
) ; synchronized ( s
) { s
. nextLine ( ) ; System . out
. println ( 1 ) ; s
. wait ( 20_0000 ) ; System . out
. println ( 2 ) ; s
. nextLine ( ) ; System . out
. println ( 3 ) ; } }
}
Thread.sleep(5000)和o.wait(5000)的區別
根本區別: 語義: sleep休眠5秒(保證一定能夠休眠5秒) wait等待通知,最多等5秒(不保證一定能休眠夠5秒,一旦被通知了,可以立即醒來) 表象區別: sleep的調用不需要持有鎖 wait休眠過程中,會釋放鎖,但只會釋放o這個對象鎖,其他持有的鎖不釋放。
package 阻塞隊列
. demo2
; import java. util. * ;
class Lock1 { }
class Lock2 { }
public class ThreadDemo2 { public static void main ( String [ ] args
) throws InterruptedException { Object lock1
= new Lock1 ( ) ; Object lock2
= new Lock2 ( ) ; Scanner s
= new Scanner ( System . in
) ; synchronized ( lock1
) { synchronized ( lock2
) { s
. nextLine ( ) ; System . out
. println ( 1 ) ;
Thread . sleep ( 5_0000 ) ; System . out
. println ( 2 ) ; s
. nextLine ( ) ; } } }
}
wait被喚醒的條件
有其他線程調用notify,并且wait的線程被選中喚醒(隨機喚醒) 有其他線程調用notifyAll 有其他線程執行類似interrupt()操作,通知線程停止,并拋出InterruptedException wait(timeout)達到超時時間時也會被喚醒 在某些系統上,由于JVM實現的原因,可能會出現虛假喚醒(上述的四個條件都沒有發生的情況下)
一般調用wait方法,我們總是期待著某些條件。 所以一般的編碼規范都是把wait放入一個循環中,循環的條件就是對我們的期望條件進行判斷。 從wait中醒來時,無法保證條件符合我們的預期了。
import java. util. concurrent. TimeUnit ; class MyThread extends Thread { @Override public void run ( ) { try { TimeUnit . SECONDS
. sleep ( 5 ) ; } catch ( InterruptedException exc
) { exc
. printStackTrace ( ) ; } synchronized ( ThreadDemo . class ) { ThreadDemo . result
= 100 ; ThreadDemo . class . notify ( ) ; } }
} public class ThreadDemo { static long result
= - 1 ; public static void main ( String [ ] args
) throws InterruptedException { MyThread thread
= new MyThread ( ) ; thread
. start ( ) ; long r
; synchronized ( ThreadDemo . class ) { ThreadDemo . class . wait ( ) ; r
= result
; } System . out
. println ( r
) ; }
}
leetcode1114 按序打印
保證操作都加鎖并且加的是同一把鎖
public class Foo { private int step
= 1 ; public Foo ( ) { } public void first ( Runnable printFirst
) throws InterruptedException { while ( true ) { synchronized ( this ) { if ( step
== 1 ) { break ; } } Thread . yield ( ) ; } wait ( ) ; printFirst
. run ( ) ; synchronized ( this ) { step
= 2 ; } } public void second ( Runnable printSecond
) throws InterruptedException { while ( true ) { synchronized ( this ) { if ( step
== 2 ) { break ; } } Thread . yield ( ) ; } printSecond
. run ( ) ; synchronized ( this ) { step
= 3 ; } } public void third ( Runnable printThird
) throws InterruptedException { while ( true ) { synchronized ( this ) { if ( step
== 3 ) { break ; } } Thread . yield ( ) ; } printThird
. run ( ) ; synchronized ( this ) { step
= 4 ; } }
}
創作挑戰賽 新人創作獎勵來咯,堅持創作打卡瓜分現金大獎
總結
以上是生活随笔 為你收集整理的多线程的通知机制 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。