线程操作wait和notify

本文介绍了Java中线程的等待(wait)与唤醒(notify和notifyAll)机制,包括如何使用这些方法控制线程间的同步与协作。文章通过具体代码示例展示了线程如何在特定条件下进入等待状态并被其他线程唤醒。

线程进入运行状态之后,可以根据条件触发转为“等待阻塞

运行的线程执行wait()方法,该线程会释放占用的所有资源,JVM会把该线程放入“等待池”中。进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒,


如下代码:

1、定义两个测试线程类

public class WaitTest1 extends Thread {
	private Object look;

	public WaitTest1(Object look) {
		this.look = look;
	}

	@Override
	public void run() {
		try {
			synchronized (look) {
				System.out.println("wait start...");
				look.wait();
				System.out.println("wait end...");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

public class WaitTest2 extends Thread {

	private Object look;

	public WaitTest2(Object look) {
		this.look = look;
	}

	@Override
	public void run() {
		try {
			synchronized (look) {
				System.out.println("notify start...");
				look.notify();
				System.out.println("notify end...");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

2、测试类

public class WaitMain {

	public static void main(String[] args) {
		try {
			Object look = "abc";
			WaitTest1 thread1 = new WaitTest1(look);
			WaitTest2 thread2 = new WaitTest2(look);

			thread1.start();
			// 两秒后唤醒
			Thread.sleep(2000);
			thread2.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}


上面代码实现了线程的等待wait和唤醒notify,运行之后输出:

wait start...
wait end...
notify start...
notify end...


说明:

在执行wait()或者notify()之前必须先获得该对象的对象级别锁,即:只能在同步方法或者同步块中调用这两个方法。

关键字synchronized可以将任何一个Object对象作为同步对象来看待,而Java为每一个Object都实现了wait()和notify()方法,
他们必须用在被synchronized同步的Object临界区内。通过调用wait()方法可以使处于临界区内的线程进入等待状态,同时释放被同步对象的锁。
而notify操作可以唤醒一个因调用了wait操作而处于阻塞状态的线程,使其进入就绪状态( 注:是就绪状态,而不是运行状态),被唤醒的线程会试图重新获得临界区的控制权,也就是锁,并继续执行临界区内wait之后的代码。
如果发出notify操作时没有处于阻塞状态的线程,那么该命令会被忽略。

wait()方法可以使调用该方法的线程释放该共享资源的锁,然后从运行状态推出,进入等待队列,直到被再次唤醒。
notify()方法可以随机唤醒等待队列中等待该共享资源的“一个”线程,并使该线程退出等待队列,进入可运行状态,也就是notify()方法仅通知"一个"线程。
notifyAll()方法可以使所有正在等待队列中等待该共享资源的“全部”线程从等待状态退出,进入可运行状态。此时优先级最高的那个线程最先执行,但也有可能是随机执行,因为这要取决于JVM虚拟机的实现。

注意方法notify()被执行后,不会释放锁,必须执行完notify()方法所在的同步synchronized代码块后才会释放锁,这一点需要注意的。

顺便附上线程状态转换图:







<think>我们正在讨论Java线程中的waitnotify方法,用于线程间通信。根据引用资料,我们可以总结以下几点: 1. wait()notify()是Object类的方法,必须在同步代码块(如synchronized块)中调用。 2. 调用wait()方法会使当前线程释放锁并进入等待状态,直到其他线程调用同一对象的notify()或notifyAll()方法。 3. notify()方法用于唤醒在该对象上等待的一个线程(任意选择),notifyAll()则唤醒所有等待线程。 4. 使用wait/notify机制可以避免轮询带来的CPU资源浪费。 下面我们通过一个示例来展示如何正确使用waitnotify实现线程间通信。</think>### Java线程waitnotify的正确使用 在Java线程编程中,`wait()``notify()`是实现**线程间通信**的核心机制,用于解决线程协作问题。以下是正确使用方法的详细说明: #### 1. 基本规则 - **调用位置**:必须在`synchronized`同步块或同步方法中调用 - **对象锁**:调用`wait()``notify()`的对象必须与同步锁对象一致 - **锁释放**:`wait()`会立即释放当前持有的锁 - **唤醒机制**: - `notify()`随机唤醒一个等待线程 - `notifyAll()`唤醒所有等待线程 - **状态转换**:`wait()`使线程进入`WAITING`状态,直到被唤醒 #### 2. 标准使用模板 ```java // 共享资源 class SharedResource { private boolean condition = false; public synchronized void waitForCondition() throws InterruptedException { while (!condition) { // 必须用while循环检查条件 wait(); // 释放锁并等待 } // 条件满足后执行任务 } public synchronized void setCondition() { condition = true; notifyAll(); // 唤醒所有等待线程 } } ``` #### 3. 典型生产消费模型示例 ```java class MessageQueue { private String message; private boolean empty = true; public synchronized String take() throws InterruptedException { while (empty) wait(); // 循环检测条件 empty = true; notifyAll(); // 唤醒生产者 return message; } public synchronized void put(String message) throws InterruptedException { while (!empty) wait(); // 循环检测条件 empty = false; this.message = message; notifyAll(); // 唤醒消费者 } } // 生产者线程 class Producer implements Runnable { private MessageQueue queue; public void run() { queue.put("Data"); // 生产数据 } } // 消费者线程 class Consumer implements Runnable { private MessageQueue queue; public void run() { String data = queue.take(); // 消费数据 } } ``` #### 4. 关键注意事项 1. **虚假唤醒防御** 必须用`while`循环而非`if`检查条件,防止虚假唤醒(spurious wakeup)[^5] ```java while (!condition) { // ✅ 正确做法 wait(); } ``` 2. **锁对象一致性** `wait()``notify()`必须作用于同一个对象锁: ```java synchronized (lock) { // 锁对象 lock.wait(); // ✅ 正确 // lock.notify(); } ``` 3. **优先使用notifyAll()** `notify()`可能因随机唤醒导致线程饥饿,`notifyAll()`更安全[^4] 4. **中断处理** `wait()`会抛出`InterruptedException`,需合理处理中断: ```java try { wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); // 恢复中断状态 } ``` #### 5. 与sleep()的区别 | 特性 | wait() | sleep() | |--------------|----------------------------------|--------------------------| | **锁释放** | 立即释放锁 | 不释放锁 | | **调用位置** | 必须在同步块内 | 任意位置 | | **唤醒方式** | 需notify()/notifyAll() | 超时自动唤醒 | | **所属类** | java.lang.Object | java.lang.Thread | #### 6. 常见错误 - **未持有锁时调用**:抛出`IllegalMonitorStateException` - **忽略中断异常**:导致线程无法响应中断 - **条件检查缺失**:未用while循环导致状态不一致 > 通过正确使用`wait()`/`notify()`机制,可有效避免轮询(busy-waiting)造成的CPU资源浪费,实现高效的线程协作[^2][^4]。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值