线程操作wait和notify

本文详细解析了Java中线程的等待(wait)与唤醒(notify)机制,通过实例代码展示了如何利用synchronized关键字和内置的wait、notify方法实现线程间的等待与唤醒,以及这些方法的工作原理和注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

运行的线程执行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代码块后才会释放锁,这一点需要注意的。

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

### 回答1: Java中的waitnotify是多线程编程中的两个重要方法,用于线程之间的协作通信。 wait方法可以使当前线程进入等待状态,直到其他线程调用notifynotifyAll方法唤醒它。在调用wait方法时,当前线程会释放它所持有的锁,以便其他线程可以访问共享资源。 notify方法用于唤醒一个处于等待状态的线程,如果有多个线程在等待,则只会唤醒其中一个线程notifyAll方法则会唤醒所有处于等待状态的线程waitnotify方法必须在同步块中使用,即在使用这两个方法的对象上获取锁。否则会抛出IllegalMonitorStateException异常。 使用waitnotify方法可以实现线程之间的协作通信,例如生产者消费者模型。在生产者消费者模型中,生产者线程生产数据并将其放入共享队列中,消费者线程从队列中取出数据并进行消费。当队列为空时,消费者线程需要等待生产者线程生产数据,此时可以使用wait方法使消费者线程进入等待状态。当生产者线程生产数据并将其放入队列中时,可以使用notify方法唤醒处于等待状态的消费者线程。 ### 回答2: Java 多线程中的 wait notify 是两个非常重要的方法,它们可以帮助线程之间达成协作,实现复杂的操作wait 方法用于让当前线程进入等待状态,直到其他线程通过 notify 方法通知它继续执行。notify 方法则用于唤醒一个等待状态的线程,使其继续执行。 wait 方法 wait 方法用于让当前线程进入等待状态,直到其他线程通过 notifynotifyAll 方法唤醒它。wait 方法需要在 synchronized 代码块中使用,否则会抛出 IllegalMonitorStateException 异常。在进入等待状态之后,线程将释放锁,并且进入一个等待池中,等待其他线程调用 notifynotifyAll 方法唤醒它。 notify 方法 notify 方法用于唤醒一个等待状态的线程,使其继续执行。notify 方法同样需要在 synchronized 代码块中使用,否则同样会抛出 IllegalMonitorStateException 异常。当一个线程调用 notify 方法时,等待池中的线程将会被唤醒,但是它们不能马上继续执行,必须等待当前线程释放锁。如果有多个线程在等待池中,notify 方法只会唤醒其中一个线程,具体唤醒哪个线程是随机的。 notifyAll 方法 notifyAll 方法notify 方法类似,但是它会唤醒所有等待池中的线程notifyAll 方法同样需要在 synchronized 代码块中使用。 使用 wait notify 实现线程协作 wait notify 方法可以用来实现线程之间的协作,例如生产者消费者问题。假设我们有一个共享的队列,生产者向队列中添加数据,消费者从队列中取出数据。如果队列已经满了,生产者就需要等待消费者取走数据,如果队列是空的,消费者就需要等待生产者加入新数据。 在这个问题中,我们可以使用 wait notify 方法来实现线程之间的协作,代码如下: ``` public class Queue { private final List<Integer> items = new LinkedList<>(); private static final int MAX_SIZE = 10; public synchronized void produce(int item) throws InterruptedException { while (items.size() == MAX_SIZE) { wait(); } items.add(item); notify(); } public synchronized int consume() throws InterruptedException { while (items.isEmpty()) { wait(); } int item = items.remove(0); notify(); return item; } } public class Producer implements Runnable { private final Queue queue; public Producer(Queue queue) { this.queue = queue; } public void run() { for (int i = 0; i < 20; i++) { try { queue.produce(i); System.out.println("Produced: " + i); } catch (InterruptedException ex) { ex.printStackTrace(); } } } } public class Consumer implements Runnable { private final Queue queue; public Consumer(Queue queue) { this.queue = queue; } public void run() { for (int i = 0; i < 20; i++) { try { int item = queue.consume(); System.out.println("Consumed: " + item); } catch (InterruptedException ex) { ex.printStackTrace(); } } } } public class Main { public static void main(String[] args) throws InterruptedException { Queue queue = new Queue(); Thread producer = new Thread(new Producer(queue)); Thread consumer = new Thread(new Consumer(queue)); producer.start(); consumer.start(); producer.join(); consumer.join(); } } ``` 在这个示例代码中,我们创建了一个 Queue 类,它有两个方法 produce consume 用于生产消费数据。在 produce 方法中,我们使用 while 循环来等待队列不满,如果队列已经满了,就调用 wait 方法进入等待状态。在 consume 方法中,我们使用 while 循环来等待队列不空,如果队列是空的,就调用 wait 方法进入等待状态。在生产新数据或者消费数据之后,我们都调用 notify 方法来唤醒等待池中的线程。 最后,我们可以使用 Producer Consumer 类来生产消费数据,它们分别运行在不同的线程中。在运行这个程序时,生产者将不断生产数据,消费者将不断消费数据,一直到数据生产完毕为止。在这个过程中,生产者消费者之间通过 wait notify 方法实现了线程之间的协作。 ### 回答3: Java是一种支持多线程的编程语言,在多线程编程过程中,一个线程可能需要等待另一个线程的某个条件满足后才能继续执行。Java提供了waitnotify来实现线程之间的协作。 wait:使当前线程进入等待状态,释放对象的锁,直到其他线程调用notifynotifyAll方法唤醒它。wait方法必须在持有对象锁的情况下调用,否则会抛出IllegalMonitorStateException异常。 notify:唤醒一个处于等待状态的线程,如果有多个线程等待,则只会唤醒其中一个,具体唤醒哪个线程无法预测。 notifyAll:唤醒所有处于等待状态的线程waitnotify必须在同步代码块中调用,并且针对同一个对象。waitnotify调用顺序也非常重要,如果先调用notify而没有等待线程,会导致唤醒失效。 在多线程编程中,waitnotify常常用于生产者消费者模式中的线程之间的通信,生产者线程在生产完毕后调用notify方法唤醒消费者线程来消费数据,消费者线程在消费完毕后调用wait方法等待下一个生产者线程的唤醒。 waitnotify的使用需要谨慎,如果使用不当,会导致死锁或线程饥饿等问题。同时,在Java SE 5之后,Java提供了更加高级的线程库,如ReentrantLock、Condition等,可以更加方便安全地实现线程之间的协作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

beyondwild

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值