深入讲解Java线程中 wait 和 notify 的用法和原理

基本概念

waitnotify 是 Java 中用于线程间通信的方法,定义在 Object 类中。它们的主要作用是在多线程环境中协调线程的执行顺序。

wait 方法

  • 作用:使当前线程进入等待状态,直到其他线程调用 notifynotifyAll 方法唤醒它。
  • 调用条件:必须在同步块或同步方法中调用,因为调用 wait 方法的线程需要持有对象的监视器锁(即对象锁)。
  • 锁释放:调用 wait 方法时,当前线程会释放对象的监视器锁,并进入该对象的等待队列中。
synchronized (lock) {
    while (!condition) {
        lock.wait();
    }
    // 执行后续操作
}

notify 方法

  • 作用:唤醒在该对象的等待队列中等待的一个线程。如果有多个线程在等待,选择其中一个线程唤醒。
  • 调用条件:必须在同步块或同步方法中调用,因为调用 notify 方法的线程需要持有对象的监视器锁。
synchronized (lock) {
    condition = true;
    lock.notify();
}

notifyAll 方法

  • 作用:唤醒在该对象的等待队列中等待的所有线程。
  • 调用条件:必须在同步块或同步方法中调用,因为调用 notifyAll 方法的线程需要持有对象的监视器锁。
synchronized (lock) {
    condition = true;
    lock.notifyAll();
}

使用场景:生产者-消费者模式

生产者-消费者模式是 waitnotify 方法的经典应用场景。在这种模式下,生产者线程生成数据,消费者线程消费数据,waitnotify 方法用于协调它们的工作。

示例代码
 
class SharedResource {
    private int content;
    private boolean available = false;

    public synchronized void put(int value) {
        while (available) {
            try {
                wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        content = value;
        available = true;
        notify();
    }

    public synchronized int get() {
        while (!available) {
            try {
                wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        available = false;
        notify();
        return content;
    }
}

class Producer implements Runnable {
    private SharedResource resource;

    public Producer(SharedResource resource) {
        this.resource = resource;
    }

    public void run() {
        for (int i = 0; i < 10; i++) {
            resource.put(i);
            System.out.println("Produced: " + i);
            try {
                Thread.sleep((int) (Math.random() * 100));
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

class Consumer implements Runnable {
    private SharedResource resource;

    public Consumer(SharedResource resource) {
        this.resource = resource;
    }

    public void run() {
        for (int i = 0; i < 10; i++) {
            int value = resource.get();
            System.out.println("Consumed: " + value);
            try {
                Thread.sleep((int) (Math.random() * 100));
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

public class ProducerConsumerTest {
    public static void main(String[] args) {
        SharedResource resource = new SharedResource();
        Thread producerThread = new Thread(new Producer(resource));
        Thread consumerThread = new Thread(new Consumer(resource));
        producerThread.start();
        consumerThread.start();
    }
}

运行效果

这段代码展示了生产者和消费者如何通过 waitnotify 方法进行协调:

Produced: 0
Consumed: 0
Produced: 1
Consumed: 1
Produced: 2
Consumed: 2
...

详细解释

  1. 生产者线程

    • 生产者线程调用 put 方法试图放入一个值。
    • 如果 availabletrue(表示已有未被消费的数据),生产者线程调用 wait 方法进入等待状态,直到消费者消费了数据并唤醒它。
    • 如果 availablefalse,生产者线程放入新值,设置 availabletrue,并调用 notify 方法唤醒一个等待的消费者线程。
  2. 消费者线程

    • 消费者线程调用 get 方法试图获取一个值。
    • 如果 availablefalse(表示没有可消费的数据),消费者线程调用 wait 方法进入等待状态,直到生产者放入新数据并唤醒它。
    • 如果 availabletrue,消费者线程获取值,设置 availablefalse,并调用 notify 方法唤醒一个等待的生产者线程。

总结

  • wait:使当前线程进入等待状态,释放对象的监视器锁。
  • notify:唤醒一个在该对象上等待的线程。
  • notifyAll:唤醒所有在该对象上等待的线程。
  • 同步块/同步方法waitnotifynotifyAll 必须在同步块或同步方法中调用,因为它们需要当前线程持有对象的监视器锁。
  • 生产者-消费者模式:经典的 waitnotify 用例,展示了如何协调多个线程对共享资源的访问。
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值