wait方法是Object中的方法,這個方法的功能特性:
1).執行wait方法的前提是當前線程已經獲取到對象的鎖,也就是wait方法必須在synchronized修飾的代碼塊或者方法中使用。
2).執行wait以後,會失去鎖的全部權
3).wait方法執行後會一直等待,直到被調用notify()、notifyAll()或者所在線程被中斷。
4).被調用notify()或者notifyAll()後,線程仍是會等待,直到擁有鎖的全部權,纔會繼續往下執行。
下面舉個例子:java
public static void main(String[] args) throws InterruptedException { Object lock1 = new Object(); Thread t1 = new Thread(new Test().new Tt1(lock1)); Thread t2 = new Thread(new Test().new Tt2(lock1)); t1.start(); Thread.sleep(1000); t2.start(); } class Tt1 implements Runnable{ private Object lock1; public Tt1(Object lock1) { this.lock1 = lock1; } @Override public void run() { try { System.out.println(this.getClass()+"-------1"); synchronized (lock1) { Thread.sleep(2000); System.out.println("waiting start"); lock1.wait(); } System.out.println("waiting end"); } catch (InterruptedException e) { e.printStackTrace(); } } } class Tt2 implements Runnable{ private Object lock1; public Tt2(Object lock1) { this.lock1 = lock1; } @Override public void run() { System.out.println(this.getClass()+"-------1"); synchronized (lock1) { try { System.out.println(this.getClass()+"-------2"); lock1.notify(); Thread.sleep(1000); System.out.println(this.getClass()+"-------3"); } catch (Exception e) { e.printStackTrace(); } } } }
執行結果:多線程
class Test$Tt1-------1 class Test$Tt2-------1 waiting start class Test$Tt2-------2 class Test$Tt2-------3 waiting end
分析一下:
第一、2行:t1和t2啓動,t1先獲取到鎖因此t2一直被阻塞住
第三、4行:t1中執行了wait,鎖被釋放,因此t2繼續執行下去。
第五、6行:t2中調用了notify()可是t1沒有立刻執行,由於鎖如今是被t2擁有,等t2執行完成釋放鎖後,t1繼續執行。ide
notify已經在上面有提到過,notify和notifyAll 的做用是喚醒正在wait的線程,notify是隨機喚醒wait線程中的一個,notifyAll 則是喚醒所有。this
1).執行notify、notifyAll 方法的前提是當前線程已經獲取到對象的鎖,也就是必須在synchronized修飾的代碼塊或者方法中使用。這個和wait是同樣的。
2).被調用notify()或者notifyAll()後,線程仍是會等待,直到擁有鎖的全部權,纔會繼續往下執行。
3)notify、notifyAll不會釋放鎖,這個與wait不一樣。線程
在多線程的操做中,鎖的釋放與否是必需要清楚的,wait是會釋放鎖,而notify(notifyAll)則不會。先舉個wait的例子:code
public static void main(String[] args) throws InterruptedException { Object lock1 = new Object(); Thread t1 = new Thread(new Test().new Tt1(lock1)); Thread t2 = new Thread(new Test().new Tt2(lock1)); t1.start(); Thread.sleep(100); t2.start(); } class Tt1 implements Runnable{ private Object lock1; public Tt1(Object lock1) { this.lock1 = lock1; } @Override public void run() { try { synchronized (lock1) { System.out.println(Thread.currentThread().getName()+"---start"); lock1.wait(); Thread.sleep(3000); System.out.println(Thread.currentThread().getName()+"---end"); } } catch (InterruptedException e) { e.printStackTrace(); } } } class Tt2 implements Runnable{ private Object lock1; public Tt2(Object lock1) { this.lock1 = lock1; } @Override public void run() { synchronized (lock1) { try { System.out.println(Thread.currentThread().getName()+"---start"); System.out.println(Thread.currentThread().getName()+"---end"); } catch (Exception e) { e.printStackTrace(); } } } }
執行結果:對象
Thread-0---start Thread-1---start Thread-1---end
Thread-0執行wait後立刻釋放了鎖,因此Thread-1很快接着就執行。get
再來notify的例子,其實就是把上一個例子wait()改爲nofity():it
public static void main(String[] args) throws InterruptedException { Object lock1 = new Object(); Thread t1 = new Thread(new Test().new Tt1(lock1)); Thread t2 = new Thread(new Test().new Tt2(lock1)); t1.start(); Thread.sleep(100); t2.start(); } class Tt1 implements Runnable{ private Object lock1; public Tt1(Object lock1) { this.lock1 = lock1; } @Override public void run() { try { synchronized (lock1) { System.out.println(Thread.currentThread().getName()+"---start"); lock1.notify(); Thread.sleep(3000); System.out.println(Thread.currentThread().getName()+"---end"); } } catch (InterruptedException e) { e.printStackTrace(); } } } class Tt2 implements Runnable{ private Object lock1; public Tt2(Object lock1) { this.lock1 = lock1; } @Override public void run() { synchronized (lock1) { try { System.out.println(Thread.currentThread().getName()+"---start"); System.out.println(Thread.currentThread().getName()+"---end"); } catch (Exception e) { e.printStackTrace(); } } } }
執行結果:io
Thread-0---start Thread-0---end Thread-1---start Thread-1---end
可見Thread-0在執行nofity後並無釋放鎖,而是等待代碼塊執行完以後才釋放鎖,Thread-1才能繼續執行。
不管是notify仍是wait都是要先獲取鎖,既必須在synchronized內使用,舉個反例:
public static void main(String[] args) throws InterruptedException { Object lock1 = new Object(); Thread t1 = new Thread(new Test().new Tt1(lock1)); t1.run(); } class Tt1 implements Runnable{ private Object lock1; public Tt1(Object lock1) { this.lock1 = lock1; } @Override public void run() { try { lock1.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } }
執行結果:
Exception in thread "main" java.lang.IllegalMonitorStateException at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Object.java:502) at Test$Tt1.run(Test.java:24) at java.lang.Thread.run(Thread.java:748) at Test.main(Test.java:11)
以前說道interrupt(),並不會直接中斷線程,而是會給線程一箇中斷標誌,並且包括sleep、wait、join會拋出InterruptedException。
public static void main(String[] args) throws InterruptedException { Object lock1 = new Object(); Thread t1 = new Thread(new Test().new Tt1(lock1)); t1.start(); Thread.sleep(100); t1.interrupt(); } class Tt1 implements Runnable{ private Object lock1; public Tt1(Object lock1) { this.lock1 = lock1; } @Override public void run() { synchronized (lock1) { try { System.out.println(Thread.currentThread().getName()+"---start"); lock1.wait(); System.out.println(Thread.currentThread().getName()+"---end"); }catch (InterruptedException e) { System.out.println("線程被中斷了");; } catch (Exception e) { e.printStackTrace(); } } } }
執行結果:
Thread-0---start 線程被中斷了
notifyAll和nofity惟一的不一樣就是,能夠喚醒所有和喚醒一個, 先舉個nofity的例子
public static void main(String[] args) throws InterruptedException { Object lock1 = new Object(); Thread t1 = new Thread(new Test().new Tt1(lock1)); Thread t2 = new Thread(new Test().new Tt1(lock1)); Thread t3 = new Thread(new Test().new Tt2(lock1)); t1.start(); Thread.sleep(100); t2.start(); Thread.sleep(100); t3.start(); } class Tt1 implements Runnable{ private Object lock1; public Tt1(Object lock1) { this.lock1 = lock1; } @Override public void run() { synchronized (lock1) { try { System.out.println(Thread.currentThread().getName()+"---start"); System.out.println(Thread.currentThread().getName()+"---wait"); lock1.wait(); System.out.println(Thread.currentThread().getName()+"---end"); } catch (Exception e) { e.printStackTrace(); } } } } class Tt2 implements Runnable{ private Object lock1; public Tt2(Object lock1) { this.lock1 = lock1; } @Override public void run() { synchronized (lock1) { try { System.out.println(Thread.currentThread().getName()+"---start"); System.out.println(Thread.currentThread().getName()+"---notify"); lock1.notify(); System.out.println(Thread.currentThread().getName()+"---end"); } catch (Exception e) { e.printStackTrace(); } } } }
執行結果:
Thread-0---start Thread-0---wait Thread-1---start Thread-1---wait Thread-2---start Thread-2---notify Thread-2---end Thread-0---end
Thread-0和Thread-1在wait,Thread-2執行了notify,但只有Thread-0被喚醒,從新開始執行,Thread-1還在wait。
再來看看nofityAll:
public static void main(String[] args) throws InterruptedException { Object lock1 = new Object(); Thread t1 = new Thread(new Test().new Tt1(lock1)); Thread t2 = new Thread(new Test().new Tt1(lock1)); Thread t3 = new Thread(new Test().new Tt2(lock1)); t1.start(); Thread.sleep(100); t2.start(); Thread.sleep(100); t3.start(); } class Tt1 implements Runnable{ private Object lock1; public Tt1(Object lock1) { this.lock1 = lock1; } @Override public void run() { synchronized (lock1) { try { System.out.println(Thread.currentThread().getName()+"---start"); System.out.println(Thread.currentThread().getName()+"---wait"); lock1.wait(); System.out.println(Thread.currentThread().getName()+"---end"); } catch (Exception e) { e.printStackTrace(); } } } } class Tt2 implements Runnable{ private Object lock1; public Tt2(Object lock1) { this.lock1 = lock1; } @Override public void run() { synchronized (lock1) { try { System.out.println(Thread.currentThread().getName()+"---start"); System.out.println(Thread.currentThread().getName()+"---notifyAll"); lock1.notifyAll(); System.out.println(Thread.currentThread().getName()+"---end"); } catch (Exception e) { e.printStackTrace(); } } } }
執行結果:
Thread-0---start Thread-0---wait Thread-1---start Thread-1---wait Thread-2---start Thread-2---notifyAll Thread-2---end Thread-1---end Thread-0---end
Thread-2執行了notifyAll後,Thread-1和Thread-0都被喚醒。