Java-多线程并发-3.Object类中的wait和notify方法

本文介绍了Java中Object类的wait和notify方法在多线程编程中的作用,它们用于线程间的协调和通信。wait()让线程等待,直到其他线程唤醒;notify()唤醒一个等待的线程,notifyAll()唤醒所有等待的线程。文章还通过生产者消费者模式展示了如何使用这两个方法来解决线程间的同步问题。
摘要由CSDN通过智能技术生成

🌐 Object类中的wait和notify方法


📌 wait()notify() 方法

  • 📚 基本信息
    • wait()notify() 是 Java 中的 Object 类的方法,而不是 Thread 类的方法。
    • 这意味着每个 Java 对象都有这两个方法。
    • 这些方法用于线程间的协调和通信。

📌 wait() 方法的作用

  • 🔄 等待

    • 当一个线程调用对象的 wait() 方法时,它会使该线程进入等待状态。
    • 该线程会持续等待,直到其他线程调用同一对象的 notify()notifyAll() 方法。
  • 📌 示例

Object o = new Object();
synchronized(o) {
    try {
        o.wait(); // 当前线程进入等待状态,直到其他线程唤醒它
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

注意: wait() 方法必须在同步代码块或同步方法中调用。


📌 notify() 方法的作用

  • 🔔 唤醒

    • 当一个线程调用对象的 notify() 方法时,它会从所有在该对象上等待的线程中选择一个来唤醒。
    • 如果有多个线程在同一对象上等待,只有一个会被 notify() 方法唤醒。
    • notifyAll() 方法则会唤醒所有在该对象上等待的线程。
  • 📌 示例

Object o = new Object();
synchronized(o) {
    o.notify(); // 唤醒在该对象上等待的一个线程
}

注意: notify()notifyAll() 也必须在同步代码块或同步方法中调用。


🌐 生产者和消费者模式

生产者和消费者模式是多线程开发中常见的设计模式,用于解决线程间的协调问题。其中,生产者负责生成数据,消费者负责处理数据。这两个角色通过一个共享的数据结构(如队列)进行通信。


📌 基本思想

  • 🏭 生产者

    • 负责产生数据。
    • 当数据结构满时,需要暂停并等待消费者处理数据。
  • 🛍️ 消费者

    • 负责处理数据。
    • 当数据结构为空时,需要暂停并等待生产者产生数据。

📌 关键点

  1. 条件检查
  • 使用while循环而不是if语句来检查条件。
  • 保证当线程被唤醒后,条件仍然满足。
  1. 锁的释放和获取
  • 调用wait()方法会释放锁。
  • 其他线程可以获取锁并执行。
  • notify()notifyAll()则是用于唤醒等待的线程。
  1. 公共的锁对象
  • wait()notify()方法需要在同一个锁对象上调用。

🎯 核心问题

  • 使用 synchronized 可以解决多线程的竞争问题。
  • synchronized 并没有解决多线程间的协调问题。

⚙️ 场景描述

  • 如果生产者生产的数据过快,消费者消费的速度跟不上。
  • 存放数据的地方(如内存缓冲区)很快就会满。
  • 如果消费者消费能力大于生产者,缓冲区很快就空了。

⚠️ 注意: 这时,消费者必须等待生产者生产数据;反之,生产者必须等待消费者消费数据。


🔗 waitnotify 的协调作用

  • synchronized 内部可以调用 wait() 使线程进入等待状态。
  • 必须在已获得的锁对象上调用 wait() 方法。
  • synchronized 内部可以调用 notify()notifyAll() 唤醒其他等待线程。
  • 必须在已获得的锁对象上调用 notify()notifyAll() 方法。
  • 已唤醒的线程还需要重新获得锁后才能继续执行。

📌 Java中的实现

Java中,可以使用Object类的wait()notify()notifyAll()方法来实现生产者和消费者模式。这些方法可以帮助我们在条件不满足时使线程进入等待状态,并在条件满足时唤醒线程。


📌 示例解析

import java.util.LinkedList;
import java.util.Queue;

public class ProducerConsumerExample {

    public static void main(String[] args) {
        TaskQueue taskQueue = new TaskQueue();

        Thread producer = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                taskQueue.addTask("Task " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Producer");

        Thread consumer = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                String task = taskQueue.getTask();
                System.out.println("Executing: " + task);
            }
        }, "Consumer");

        producer.start();
        consumer.start();
    }
}

class TaskQueue {
    private Queue<String> queue = new LinkedList<>();

    public synchronized void addTask(String task) {
        queue.add(task);
        notify();
    }

    public synchronized String getTask() {
        while (queue.isEmpty()) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return queue.poll();
    }
}

📌 说明

  • TaskQueue类是共享数据结构,生产者往其中添加任务,消费者从中取出任务。
  • 生产者线程和消费者线程分别是两个独立的线程。生产者每0.5秒生产一个任务,消费者则尝试获取并执行任务。
  • 当队列为空时,消费者会进入等待状态;生产者在添加任务后会唤醒等待的消费者线程。

这只是一个简单的生产者和消费者模式的实现。在实际应用中,可能还需要考虑更多细节和其他因素,例如支持多个生产者和消费者、设置队列的最大容量、处理异常等。


📌 总结

生产者和消费者模式是解决线程间协调问题的经典模式。在Java中,通过Object类的wait()notify()方法,我们可以很容易地实现这个模式。但要确保正确地使用这些方法,避免出现死锁或线程饿死的情况。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

yueerba126

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

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

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

打赏作者

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

抵扣说明:

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

余额充值