26.wait()、notify()和notifyAll()方法

本文深入探讨了Java中线程同步的三大核心方法:wait()、notify()和notifyAll()。详细解释了这些方法如何在多线程环境中实现线程间的等待与唤醒,以及它们在同步代码块中的正确使用方式。

一.wait()

该方法用来将当前线程置入休眠状态,直到接到通知或被中断为止。在调用wait()之前,线程必须要获得该对象的对象级别锁,即只能在同步方法或同步块中调用wait()方法进入wait()方法后,当前线程释放锁。在从wait()返回前,线程与其他线程竞争重新获得锁。如果调用wait()时,没有持有适当的锁,则抛出IllegalMonitorStateException,它是RuntimeException的一个子类,因此,不需要try-catch结构。

总结:

  • 是Object的方法
  • 调用方式:对象.wait();
  • 表示释放 “对象” 这个锁标记,然后在锁外边等待(对比sleep(),sleep是抱着锁休眠的)
  • 等待,必须放到同步代码段中执行

二.notify()

该方法用来通知那些可能等待该对象的对象锁的其他线程。
如果有多个线程等待,则线程规划器任意挑出其中一个wait()状态的线程来发出通知,并使它等待获取该对象的对象锁(notify后,当前线程不会马上释放该对象锁,wait所在的线程并不能马上获取该对象锁,要等到程序退出synchronized代码块后,当前线程才会释放锁,wait所在的线程也才可以获取该对象锁),但不惊动其他同样在等待被该对象notify的线程们。当第一个获得了该对象锁的wait线程运行完毕以后,它会释放掉该对象锁,此时如果该对象没有再次使用notify语句,则即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,会继续阻塞在wait状态,直到这个对象发出一个notify或notifyAll。这里需要注意它们等待的是被notify或notifyAll,而不是锁。这与下面的notifyAll()方法执行后的情况不同.

总结:

  • 是Object的方法
  • 调用方式:对象.notify();
  • 表示唤醒 对象 所标记外边在等待的随机唤醒一个处于wait()状态的线程

三.notifyAll()

该方法与notify()方法的工作方式相同,重要的一点差异是:
notifyAll使所有原来在该对象上wait的线程统统退出wait的状态(即全部被唤醒,不再等待notify或notifyAll,但由于此时还没有获取到该对象锁,因此还不能继续往下执行),变成等待获取该对象上的锁,一旦该对象锁被释放(notifyAll线程退出调用了notifyAll的synchronized代码块的时候),他们就会去竞争。如果其中一个线程获得了该对象锁,它就会继续往下执行,在它退出synchronized代码块,释放锁后,其他的已经被唤醒的线程将会继续竞争获取该锁,一直进行下去,直到所有被唤醒的线程都执行完毕。

总结:

  • 是Object的方法
  • 调用方式:对象.notifyAll()
  • 表示唤醒 对象 所标记外边等待的所有线程
在 Java 中,`wait()`、`notify()` `notifyAll()` 是 `Object` 类的方法,用于线程间的协作同步,它们构成了内部条件队列的 API,能让线程在特定条件下等待或被唤醒[^3]。 ### 方法介绍 - **`wait()`**:该方法用于使当前线程进入等待状态,直到其他线程调用此对象的 `notify()` 方法或 `notifyAll()` 方法。调用 `wait()` 方法前,当前线程必须先获得该对象的,调用后线程会释放对象的,并进入该对象的等待队列。只有当其他线程调用 `notify()` 或 `notifyAll()` 方法唤醒等待线程,且该线重新获得对象的后,才会继续执行后续代。`wait()` 方法有两种重载形式:`wait()` `wait(long timeout)`,后者可以指定等待的最长时间,超时后线程会自动唤醒。 ```java public class WaitExample { public static void main(String[] args) { final Object lock = new Object(); Thread t1 = new Thread(() -> { synchronized (lock) { try { System.out.println("线程1开始等待"); lock.wait(); System.out.println("线程1被唤醒,继续执行"); } catch (InterruptedException e) { e.printStackTrace(); } } }); t1.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock) { lock.notify(); System.out.println("主线程唤醒线程1"); } } } ``` - **`notify()`**:用于唤醒在此对象监视器上等待的单个线程。如果有多个线程在等待,则由 JVM 随机选择一个线程唤醒。调用 `notify()` 方法前,当前线程必须先获得该对象的,调用后不会立即释放对象的,而是继续执行 `synchronized` 代块中的代,直到执行完或中途遇到 `wait()` 方法,才会释放。 ```java public class NotifyExample { public static void main(String[] args) { final Object lock = new Object(); Thread t1 = new Thread(() -> { synchronized (lock) { try { System.out.println("线程1开始等待"); lock.wait(); System.out.println("线程1被唤醒,继续执行"); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread t2 = new Thread(() -> { synchronized (lock) { try { System.out.println("线程2开始等待"); lock.wait(); System.out.println("线程2被唤醒,继续执行"); } catch (InterruptedException e) { e.printStackTrace(); } } }); t1.start(); t2.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock) { lock.notify(); System.out.println("主线程唤醒一个等待线程"); } } } ``` - **`notifyAll()`**:用于唤醒在此对象监视器上等待的所有线程。调用 `notifyAll()` 方法前,当前线程必须先获得该对象的,调用后不会立即释放对象的,而是继续执行 `synchronized` 代块中的代,直到执行完或中途遇到 `wait()` 方法,才会释放。被唤醒的线程竞争对象的获得线程才能继续执行后续代。 ```java public class NotifyAllExample { public static void main(String[] args) { final Object lock = new Object(); Thread t1 = new Thread(() -> { synchronized (lock) { try { System.out.println("线程1开始等待"); lock.wait(); System.out.println("线程1被唤醒,继续执行"); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread t2 = new Thread(() -> { synchronized (lock) { try { System.out.println("线程2开始等待"); lock.wait(); System.out.println("线程2被唤醒,继续执行"); } catch (InterruptedException e) { e.printStackTrace(); } } }); t1.start(); t2.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock) { lock.notifyAll(); System.out.println("主线程唤醒所有等待线程"); } } } ``` ### 特点性质 - 调用 `wait()`、`notify()` `notifyAll()` 方法前,必须先获得对象的,即这些方法必须在 `synchronized` 代块或 `synchronized` 方法中调用[^1]。 - `notify()` 只能随机唤醒一个等待线程,具体由 JVM 决定;`notifyAll()` 会唤醒所有等待线程[^2]。 - 这些方法都属于 `Object` 类,任何对象都可以调用它们,且它们都是 `native` 方法,具体实现位于 JVM 层[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值