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用法的实现原理和使用方法。