wati notify notifyAll 都是Object的方法java
常常與synchronized關鍵字配合使用ide
咱們用個列子來講明下spa
public class notifyWait { private static int m =0; public static void main(String[] args) { // TODO Auto-generated method stub final Object lock = new Object(); Thread t1 = new Thread( new Runnable(){ @Override public void run() { synchronized (lock) { System.out.println("t1啓動.."); // TODO Auto-generated method stub for (int i = 0; i < 50; i++) { System.out.println("當前線程:" + Thread.currentThread().getName()+"i=="+i); if (i == 5) { System.out.println("喚醒t2線程"); lock.notifyAll();//不釋放鎖 t2線程雖然被喚醒 但 操做系統時間片任然在t1線程 } m++; } } }} ); Thread t2 = new Thread( new Runnable(){ @Override public void run() { synchronized (lock) { // TODO Auto-generated method stub if (m != 5) { try { lock.wait();//等待 釋放鎖 System.out.println("t2 啓動");//從新喚醒後外面的判斷沒影響 System.out.println("t2被喚醒"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }}); t2.start(); t1.start(); } }
建立t1 t2兩個線程 兩個線程啓動執行run裏面的方法時要得到 lock方法的鎖操作系統
分別啓動 t2 t1線程 代碼裏面能夠看出線程
t2線程啓動時 先得到lock鎖 而後調用 wait方法 t2線程讓出cpu執行時間 進入lock對象的休息區休息(wait方法釋放鎖)code
t1線程啓動後 知足必定條件後在lock對象上調用 notifyAll方法 喚醒在lock對象上等待的線程(notify 喚醒一個等待線程,但不肯定是哪個 ,notifyAll喚醒全部在lock對象上休眠的線程 ,我通常都使用notify方法,固然若是能肯定等待的線程只有一個也可以使用notify方法)對象
運行結果get
t1啓動.. 當前線程:Thread-0i==0 當前線程:Thread-0i==1 當前線程:Thread-0i==2 當前線程:Thread-0i==3 當前線程:Thread-0i==4 當前線程:Thread-0i==5 喚醒t2線程 當前線程:Thread-0i==6 當前線程:Thread-0i==7 當前線程:Thread-0i==8 當前線程:Thread-0i==9 當前線程:Thread-0i==10 當前線程:Thread-0i==11 當前線程:Thread-0i==12 當前線程:Thread-0i==13 當前線程:Thread-0i==14 當前線程:Thread-0i==15 當前線程:Thread-0i==16 當前線程:Thread-0i==17 當前線程:Thread-0i==18 當前線程:Thread-0i==19 當前線程:Thread-0i==20 當前線程:Thread-0i==21 當前線程:Thread-0i==22 當前線程:Thread-0i==23 當前線程:Thread-0i==24 當前線程:Thread-0i==25 當前線程:Thread-0i==26 當前線程:Thread-0i==27 當前線程:Thread-0i==28 當前線程:Thread-0i==29 當前線程:Thread-0i==30 當前線程:Thread-0i==31 當前線程:Thread-0i==32 當前線程:Thread-0i==33 當前線程:Thread-0i==34 當前線程:Thread-0i==35 當前線程:Thread-0i==36 當前線程:Thread-0i==37 當前線程:Thread-0i==38 當前線程:Thread-0i==39 當前線程:Thread-0i==40 當前線程:Thread-0i==41 當前線程:Thread-0i==42 當前線程:Thread-0i==43 當前線程:Thread-0i==44 當前線程:Thread-0i==45 當前線程:Thread-0i==46 當前線程:Thread-0i==47 當前線程:Thread-0i==48 當前線程:Thread-0i==49 t2 啓動 t2被喚醒
這個結果代表線程 t1 在執行到i 等於5的時候 向在lock對象上休眠的對象發出了喚醒通知 並且 後面it
t2也確實被喚醒了(打印了t2啓動 t2被喚醒);io
如今 有一個問題 就是t1在喚醒t2後 還接着把循環打印完 而後 t2纔開始 執行實際的方法,
這是由於 notify notifyAll不釋放鎖 雖然t1 把t2喚醒了 可是 lock對象的鎖還在t1上 ,因此t1會先執行完。
也就是喚醒不及時 t2被喚醒後 沒能及時處理本身的邏輯
針對這個問題咱們能夠java.util.concurrent下的CountDownLatch來處理
public class CountDownLatchnotify { private static int m =0; public static void main(String[] args) { // TODO Auto-generated method stub final Object lock = new Object(); final CountDownLatch c = new CountDownLatch(1); Thread t1 = new Thread( new Runnable(){ @Override public void run() { System.out.println("t1啓動.."); // TODO Auto-generated method stub for (int i = 0; i < 50; i++) { System.out.println("當前線程:" + Thread.currentThread().getName()+"i=="+i); if (i == 5) { System.out.println("喚醒t2線程"); c.countDown(); } m++; } }} ); Thread t2 = new Thread( new Runnable(){ @Override public void run() { // TODO Auto-generated method stub if (m != 5) { try { c.await(); System.out.println("t2 啓動"); System.out.println("t2 被喚醒"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }}); t2.start(); t1.start(); } }
在CountDownLatch調用await方法線程進入休眠狀態 直到CountDownLatch的計數器爲0 立刻被喚醒
運行結果
t1啓動.. 當前線程:Thread-0i==0 當前線程:Thread-0i==1 當前線程:Thread-0i==2 當前線程:Thread-0i==3 當前線程:Thread-0i==4 當前線程:Thread-0i==5 喚醒t2線程 當前線程:Thread-0i==6 t2 啓動 t2 被喚醒 當前線程:Thread-0i==7 當前線程:Thread-0i==8 當前線程:Thread-0i==9 當前線程:Thread-0i==10 當前線程:Thread-0i==11 當前線程:Thread-0i==12 當前線程:Thread-0i==13 當前線程:Thread-0i==14 當前線程:Thread-0i==15 當前線程:Thread-0i==16 當前線程:Thread-0i==17 當前線程:Thread-0i==18 當前線程:Thread-0i==19 當前線程:Thread-0i==20 當前線程:Thread-0i==21 當前線程:Thread-0i==22 當前線程:Thread-0i==23 當前線程:Thread-0i==24 當前線程:Thread-0i==25 當前線程:Thread-0i==26 當前線程:Thread-0i==27 當前線程:Thread-0i==28 當前線程:Thread-0i==29 當前線程:Thread-0i==30 當前線程:Thread-0i==31 當前線程:Thread-0i==32 當前線程:Thread-0i==33 當前線程:Thread-0i==34 當前線程:Thread-0i==35 當前線程:Thread-0i==36 當前線程:Thread-0i==37 當前線程:Thread-0i==38 當前線程:Thread-0i==39 當前線程:Thread-0i==40 當前線程:Thread-0i==41 當前線程:Thread-0i==42 當前線程:Thread-0i==43 當前線程:Thread-0i==44 當前線程:Thread-0i==45 當前線程:Thread-0i==46 當前線程:Thread-0i==47 當前線程:Thread-0i==48 當前線程:Thread-0i==49