Java中的wait()方法是實現線程同步的重要手段之一,它可以讓線程等待其他線程的通知或者到達某個狀態再執行,有助於優化程序性能。本文將從多個角度詳細介紹Java Wait用法。
一、wait()方法的作用及基本用法
Java中的wait()方法可以讓一個線程等待另一個線程發出的通知或者到達某個狀態再執行,主要用於實現線程之間的同步和協作。因為Java中的線程是資源共享的,線程之間的訪問需要協調和同步,wait()方法就是一種實現線程同步的手段。
wait()方法的基本用法如下:
public synchronized void wait() throws InterruptedException
在synchronized方法中調用wait()方法時,當前線程進入等待狀態,直到其他線程調用notify()或者notifyAll()方法通知當前線程,或者等待時間耗盡才結束等待狀態。
wait()方法的示例代碼:
public class ThreadTest { public static void main(String[] args) throws InterruptedException { Object lock = new Object(); Thread thread1 = new Thread(() -> { synchronized (lock) { try { System.out.println(Thread.currentThread().getName() + " start waiting..."); lock.wait(); System.out.println(Thread.currentThread().getName() + " end waiting..."); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread thread2 = new Thread(() -> { synchronized (lock) { System.out.println(Thread.currentThread().getName() + " notify..."); lock.notify(); } }); thread1.start(); Thread.sleep(1000); thread2.start(); } }
上述示例代碼中,thread1線程調用了wait()方法,進入等待狀態,直到thread2線程調用了notify()方法之後,才結束等待狀態。
二、wait()方法與notify()方法的配對使用
在使用wait()方法時,需要與notify()方法配對使用,notify()方法可以喚醒等待狀態的線程,讓它重新開始執行。
notify()方法的基本用法如下:
public final native void notify()
notify()方法的典型用法如下:
public class ThreadTest { public static void main(String[] args) throws InterruptedException { Object lock = new Object(); Thread thread1 = new Thread(() -> { synchronized (lock) { try { System.out.println(Thread.currentThread().getName() + " start waiting..."); lock.wait(); System.out.println(Thread.currentThread().getName() + " end waiting..."); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread thread2 = new Thread(() -> { synchronized (lock) { System.out.println(Thread.currentThread().getName() + " notify..."); lock.notify(); } }); thread1.start(); Thread.sleep(1000); thread2.start(); } }
上述示例中,thread1線程調用了wait()方法進入等待狀態,直到thread2線程調用了notify()方法喚醒thread1線程,thread1線程才結束等待狀態並重新執行。
三、wait()方法和notify()方法的注意事項
1. wait()方法和notify()方法只能在synchronized代碼塊中使用
由於wait()方法和notify()方法需要對共享變量進行操作,因此只能在synchronized代碼塊中使用,否則會拋出IllegalMonitorStateException異常。
下面是一個使用wait()方法和notify()方法的非法示例:
public class ThreadTest { private static Object lock = new Object(); public static void main(String[] args) throws InterruptedException { Thread thread1 = new Thread(() -> { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } }); Thread thread2 = new Thread(() -> { lock.notify(); }); thread1.start(); Thread.sleep(1000); thread2.start(); } }
上述代碼中,wait()方法和notify()方法不在synchronized代碼塊中使用,因此會拋出IllegalMonitorStateException異常。
2. wait()方法必須放在循環中使用
在使用wait()方法時,為了避免虛假喚醒問題(即線程沒有收到notify()通知,但是等待結束了),wait()方法必須放在循環中使用,如下所示:
public class ThreadTest { private static Object lock = new Object(); public static void main(String[] args) throws InterruptedException { Thread thread1 = new Thread(() -> { synchronized (lock) { while (true) { try { System.out.println(Thread.currentThread().getName() + " start waiting..."); lock.wait(); System.out.println(Thread.currentThread().getName() + " end waiting..."); } catch (InterruptedException e) { e.printStackTrace(); } } } }); Thread thread2 = new Thread(() -> { synchronized (lock) { System.out.println(Thread.currentThread().getName() + " notify..."); lock.notify(); } }); thread1.start(); Thread.sleep(1000);//等待線程1進入wait狀態 thread2.start(); } }
上述代碼中,wait()方法放在while循環中使用,當線程被虛假喚醒時,會重新進入循環,直到收到notify()通知才結束等待狀態。
3. notify()方法不會釋放鎖
在調用notify()方法時,不會釋放鎖,因此在執行完notify()方法之後,線程仍然會保持鎖定狀態,在synchronized代碼塊中繼續執行。
下面是一個示例代碼:
public class ThreadTest { private static Object lock = new Object(); public static void main(String[] args) throws InterruptedException { Thread thread1 = new Thread(() -> { synchronized (lock) { try { System.out.println(Thread.currentThread().getName() + " start waiting..."); lock.wait(); System.out.println(Thread.currentThread().getName() + " end waiting..."); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread thread2 = new Thread(() -> { synchronized (lock) { System.out.println(Thread.currentThread().getName() + " notify..."); lock.notify(); System.out.println(Thread.currentThread().getName() + " do something after notify..."); } }); thread1.start(); Thread.sleep(1000); thread2.start(); } }
上述代碼中,當thread2線程調用notify()方法時,僅僅喚醒了thread1線程,而不會釋放鎖,因此thread2線程在執行完notify()方法之後,仍然在synchronized代碼塊中執行,直到執行完畢後才釋放鎖。
四、wait()方法的其他用法
除了基本用法外,wait()方法還可以通過指定等待時間或者超時時間,來控制等待狀態的結束,具體如下:
1. 指定等待時間
wait()方法可以指定等待時間,單位為毫秒,如果在指定時間內,其他線程沒有調用notify()方法通知當前線程,那麼當前線程會自動結束等待狀態,繼續向下執行。
wait()方法的用法如下:
public synchronized void wait(long timeout) throws InterruptedException public final native void wait(long timeout, int nanos) throws InterruptedException
示例代碼如下:
public class ThreadTest { public static void main(String[] args) throws InterruptedException { Object lock = new Object(); Thread thread1 = new Thread(() -> { synchronized (lock) { try { System.out.println(Thread.currentThread().getName() + " start waiting for 2 seconds..."); lock.wait(2000); System.out.println(Thread.currentThread().getName() + " end waiting..."); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread thread2 = new Thread(() -> { synchronized (lock) { System.out.println(Thread.currentThread().getName() + " notify..."); lock.notify(); } }); thread1.start(); Thread.sleep(1000); thread2.start(); } }
上述示例中,thread1線程調用了wait(2000)方法,等待2秒後自動結束等待狀態執行,即使此時還沒有收到notify()通知。
2. 超時時間
wait()方法還可以通過指定超時時間來控制等待狀態的結束,單位為納秒,如果在指定時間內,其他線程沒有調用notify()方法通知當前線程,那麼當前線程會自動結束等待狀態,繼續向下執行。
wait()方法的用法如下:
public final native void wait(long timeout, int nanos) throws InterruptedException
示例代碼如下:
public class ThreadTest { public static void main(String[] args) throws InterruptedException { Object lock = new Object(); Thread thread1 = new Thread(() -> { synchronized (lock) { try { System.out.println(Thread.currentThread().getName() + " start waiting..."); long start = System.nanoTime(); lock.wait(1000, 500); long end = System.nanoTime(); System.out.println(Thread.currentThread().getName() + " end waiting..., elapsed time: " + (end - start) + "ns"); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread thread2 = new Thread(() -> { synchronized (lock) { System.out.println(Thread.currentThread().getName() + " notify..."); lock.notify(); } }); thread1.start(); Thread.sleep(1000); thread2.start(); } }
上述示例中,thread1線程調用了wait(1000, 500)方法,等待1秒500納秒後自動結束等待狀態執行,即使此時還沒有收到notify()通知。
五、總結
本文從wait()方法的作用及基本用法、wait()方法與notify()方法的配對使用、wait()方法和notify()方法的注意事項、wait()方法的其他用法等多個方面對Java Wait用法做了詳細的闡述,並給出了相應的示例代碼,希望能夠幫助讀者深入理解Java Wait用法的實現原理和使用方法。
原創文章,作者:JMPC,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/140805.html