Java Object對象中的wait,notify,notifyAll的理解
wait,notify,notifyAll 是定義在Object類的實例方法,用於控制線程狀態,在線程協作時,大家都會用到notify()或者notifyAll()方法,其中wait與notify是java同步機制中重要的組成部分,需要結合與synchronized關鍵字才能使用,在調用一個Object的wait與notify/notifyAll的時候,必須保證調用代碼對該Object是同步的,也就是說必須在作用等同於synchronized(object){......}的內部才能夠去調用obj的wait與notify/notifyAll三個方法,否則就會報錯:java.lang.IllegalMonitorStateException:current thread not owner(意思是因為沒有同步,所以線程對對象鎖的狀態是不確定的,不能調用這些方法)。
wait的目的就在於暴露出對象鎖,所以需要保證在lock的同步代碼中調用lock.wait()方法,讓其他線程可以通過對象的notify叫醒等待在該對象的等該池裏的線程。同樣notify也會釋放對象鎖,在調用之前必須獲得對象的鎖,不然也會報異常。所以,在線程自動釋放其占有的對象鎖後,不會去申請對象鎖,只有當線程被喚醒的時候或者達到最大的睡眠時間,它才再次爭取對象鎖的權利
主要方法:
(1).wait()
等待對象的同步鎖,需要獲得該對象的同步鎖才可以調用這個方法,否則編譯可以通過,但運行時會收到一個異常:IllegalMonitorStateException。調用任意對象的 wait() 方法導致該線程阻塞,該線程不可繼續執行,並且該對象上的鎖被釋放。
(2).notify()
喚醒在等待該對象同步鎖的線程(只喚醒一個,如果有多個在等待),註意的是在調用此方法的時候,並不能確切的喚醒某一個等待狀態的線程,而是由JVM確定喚醒哪個線程,而且不是按優先級。調用任意對象的notify()方法則導致因調用該對象的 wait()方法而阻塞的線程中隨機選擇的一個解除阻塞(但要等到獲得鎖後才真正可執行)。
(3).notifyAll()
喚醒所有等待的線程,註意喚醒的是notify之前wait的線程,對於notify之後的wait線程是沒有效果的。
通過一個實例來看一下實際的效果,開啟兩個線和,一個線程 打印1到52的數字,一個打印A到Z的字母,要求,打印兩個數,打印一個字母,這樣交替順序打印,代碼如下:
/** * create by spy on 2018/6/4 */ public class ShuZiZiMuThread { public static void main(String[] args) { Object object = new Object(); shuzi shuzi = new shuzi(object); zimu zimu = new zimu(object); Thread t = new Thread(shuzi); t.setName("shuzi"); Thread t1 = new Thread(zimu); t1.setName("zimu"); t.start();//數字線程先運行 t1.start(); } } class shuzi implements Runnable{ private Object object; //聲明類的引用 public shuzi(Object object) { this.object = object; } public void run() { synchronized (object) {//上鎖 for(int i=1;i<53;i++){ System.out.print(i+","); if(i%2==0){ object.notifyAll();//喚醒其它爭奪權限的線程 try { object.wait();//釋放鎖,進入等待 System.out.println("數字打印類打全打印當前對象擁有對象鎖的線程"+Thread.currentThread().getName());//輸出當前擁有鎖的線程名稱 } catch (InterruptedException e) { e.printStackTrace(); } } } } } } class zimu implements Runnable{ private Object object; public zimu(Object object) { this.object = object; } public void run() { synchronized (object) { for(int j=65;j<91;j++){ char c = (char)j; System.out.print(c); object.notifyAll();//喚醒其它爭奪權限的線程 try { object.wait();//釋放鎖,進入等待 System.out.println("字母打印類打全打印當前對象擁有對象鎖的線程"+Thread.currentThread().getName());//輸出當前擁有鎖的線程名稱 } catch (InterruptedException e) { e.printStackTrace(); } } } } }
實際運行的結果 :
1,2,A數字打印類打印當前對象擁有對象鎖的線程shuzi
3,4,字母打印類打印當前對象擁有對象鎖的線程zimu
B數字打印類打印當前對象擁有對象鎖的線程shuzi
5,6,字母打印類打印當前對象擁有對象鎖的線程zimu
C數字打印類打印當前對象擁有對象鎖的線程shuzi
7,8,字母打印類打印當前對象擁有對象鎖的線程zimu
D數字打印類打印當前對象擁有對象鎖的線程shuzi
9,10,字母打印類打印當前對象擁有對象鎖的線程zimu
E數字打印類打印當前對象擁有對象鎖的線程shuzi
11,12,字母打印類打印當前對象擁有對象鎖的線程zimu
F數字打印類打印當前對象擁有對象鎖的線程shuzi
13,14,字母打印類打印當前對象擁有對象鎖的線程zimu
G數字打印類打印當前對象擁有對象鎖的線程shuzi
15,16,字母打印類打印當前對象擁有對象鎖的線程zimu
H數字打印類打印當前對象擁有對象鎖的線程shuzi
17,18,字母打印類打印當前對象擁有對象鎖的線程zimu
I數字打印類打印當前對象擁有對象鎖的線程shuzi
19,20,字母打印類打印當前對象擁有對象鎖的線程zimu
J數字打印類打印當前對象擁有對象鎖的線程shuzi
21,22,字母打印類打印當前對象擁有對象鎖的線程zimu
K數字打印類打印當前對象擁有對象鎖的線程shuzi
23,24,字母打印類打印當前對象擁有對象鎖的線程zimu
L數字打印類打印當前對象擁有對象鎖的線程shuzi
25,26,字母打印類打印當前對象擁有對象鎖的線程zimu
M數字打印類打印當前對象擁有對象鎖的線程shuzi
27,28,字母打印類打印當前對象擁有對象鎖的線程zimu
N數字打印類打印當前對象擁有對象鎖的線程shuzi
29,30,字母打印類打印當前對象擁有對象鎖的線程zimu
O數字打印類打印當前對象擁有對象鎖的線程shuzi
31,32,字母打印類打印當前對象擁有對象鎖的線程zimu
P數字打印類打印當前對象擁有對象鎖的線程shuzi
33,34,字母打印類打印當前對象擁有對象鎖的線程zimu
Q數字打印類打印當前對象擁有對象鎖的線程shuzi
35,36,字母打印類打印當前對象擁有對象鎖的線程zimu
R數字打印類打印當前對象擁有對象鎖的線程shuzi
37,38,字母打印類打印當前對象擁有對象鎖的線程zimu
S數字打印類打印當前對象擁有對象鎖的線程shuzi
39,40,字母打印類打印當前對象擁有對象鎖的線程zimu
T數字打印類打印當前對象擁有對象鎖的線程shuzi
41,42,字母打印類打印當前對象擁有對象鎖的線程zimu
U數字打印類打印當前對象擁有對象鎖的線程shuzi
43,44,字母打印類打印當前對象擁有對象鎖的線程zimu
V數字打印類打印當前對象擁有對象鎖的線程shuzi
45,46,字母打印類打印當前對象擁有對象鎖的線程zimu
W數字打印類打印當前對象擁有對象鎖的線程shuzi
47,48,字母打印類打印當前對象擁有對象鎖的線程zimu
X數字打印類打印當前對象擁有對象鎖的線程shuzi
49,50,字母打印類打印當前對象擁有對象鎖的線程zimu
Y數字打印類打印當前對象擁有對象鎖的線程shuzi
51,52,字母打印類打印當前對象擁有對象鎖的線程zimu
Z數字打印類打印當前對象擁有對象鎖的線程shuzi
結果分析:
通過結果可以看出:
在字母打一打印類裏 調用完
object.notifyAll();//喚醒其它爭奪權限的線程
object.wait();//釋放鎖,進入等待
後,擁有對象鎖的線程是shuzi
在數字打印類裏 調用完
object.notifyAll();//喚醒其它爭奪權限的線程
object.wait();//釋放鎖,進入等待
後,擁有對象鎖的線程是zimu
Java Object對象中的wait,notify,notifyAll的理解