问:说说notify()和notifyAll()有什么区别?

news/2024/9/20 7:38:58 标签: java, 开发语言

notify()notifyAll() 是 Java 中用于线程间通信的方法,这两个方法都用于唤醒正在等待 (wait()) 的线程。然而,它们在工作方式和应用场景上有一些重要的区别。

notify() vs notifyAll()

  1. notify():

    • 唤醒一个正在等待 (wait()) 的线程。
    • 如果有多个线程在等待,具体唤醒哪一个线程是不确定的。
    • 可能导致死锁,如果唤醒的线程不能使等待条件变为真,而其他线程仍然需要等待。
  2. notifyAll():

    • 唤醒所有正在等待 (wait()) 的线程。
    • 确保所有等待的线程都有机会检查等待条件。

示例

假设有一个资源池,其中有一定数量的资源,线程可以从中获取资源。如果资源池为空,线程需要等待直到有资源可用。

java">import java.util.LinkedList;
import java.util.Queue;

public class ResourcePool {
    private final Queue<String> pool = new LinkedList<>();
    private final int capacity;

    public ResourcePool(int capacity) {
        this.capacity = capacity;
    }

    public synchronized void produce(String resource) throws InterruptedException {
        while (pool.size() == capacity) {
            wait();
        }
        pool.add(resource);
        notifyAll(); // 通知所有等待的线程资源可能可用
    }

    public synchronized String consume() throws InterruptedException {
        while (pool.isEmpty()) {
            wait();
        }
        String resource = pool.poll();
        notifyAll(); // 通知所有等待的线程可能有空间可用
        return resource;
    }

    public static void main(String[] args) {
        ResourcePool pool = new ResourcePool(2);

        // Producer thread
        Thread producer = new Thread(() -> {
            try {
                for (int i = 1; i <= 5; i++) {
                    pool.produce("Resource " + i);
                    System.out.println("Produced Resource " + i);
                    Thread.sleep(500); // 模拟生产时间
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // Consumer thread
        Thread consumer = new Thread(() -> {
            try {
                for (int i = 1; i <= 5; i++) {
                    String resource = pool.consume();
                    System.out.println("Consumed " + resource);
                    Thread.sleep(1000); // 模拟消费时间
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

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

说明

  1. while 循环与 wait():

    • 在调用 wait() 之前,应该使用 while 循环来检查等待条件。这是因为 wait() 可能会在条件尚未满足时被中断(例如,由 notifyAll() 唤醒,但条件仍未满足)。
    • produce()consume() 方法中,使用 while 循环来确保在调用 wait() 前后都检查条件。
  2. notify() 可能导致死锁:

    • 如果我们使用 notify() 而不是 notifyAll(),可能会唤醒一个不能使条件变为真的线程,而其他线程仍然需要等待,导致死锁。
    • 在上面的例子中,如果我们使用 notify(),可能会出现生产者线程唤醒另一个生产者线程(而资源池已满),或者消费者线程唤醒另一个消费者线程(而资源池为空)的情况,导致死锁。
  3. notifyAll() 确保所有线程都有机会检查条件:

    • 使用 notifyAll() 可以确保所有等待的线程都被唤醒,并且都有机会检查等待条件是否满足。
    • 在上面的代码中,notifyAll() 确保无论是生产者还是消费者线程,都能在资源池状态改变时被唤醒,并检查条件是否满足。

结语

  • 使用 notify() 需要非常小心,确保唤醒的线程能够正确处理接下来的事项,否则可能导致死锁。
  • notifyAll() 更加安全和保守,适用于大多数场景,确保所有等待的线程都有机会检查条件。
  • 在使用 wait() 时,应配合 while 循环使用,以确保在条件不满足时能够重新进入等待状态。

http://www.niftyadmin.cn/n/5666828.html

相关文章

使用Python-pptx轻松搜索和替换PPT中的文本

哈喽,大家好,我是木头左! 本文将详细介绍如何使用Python-pptx来搜索并替换PPT文档中的特定文本。 安装Python-pptx库 确保你已经安装了Python-pptx库。如果没有,可以通过以下命令进行安装: pip install python-pptx导入所需模块 在开始编写代码之前,需要导入Python-p…

苹果CMS插件:优化蜘蛛访问内容,提升百度收录率

确保蜘蛛抓取原始内容 专为苹果CMS设计的广告管理插件&#xff0c;能够智能识别搜索引擎蜘蛛与普通访客&#xff0c;确保蜘蛛访问时展示原始内容&#xff0c;从而提升被百度等搜索引擎收录的几率。 广告显示提升收益 对于普通访客&#xff0c;该插件则优先显示广告内容&#…

记一次键盘f2和f5键被自动触发情况

背景&#xff1a; 联想小新笔记本电脑内置键盘&#xff0c;其中f2键和f5键一直被自动触发&#xff0c;已尝试过更换输入法&#xff0c;重装系统&#xff0c;拆开键帽清灰依旧无效。考虑维修费或者更换键盘&#xff08;内置&#xff09;费都挺贵的&#xff0c;而且f2和f5作用也…

Nginx从入门到入土(三): 静态资源管理与代理服务

软负载和硬负载的区别 软负载均衡是通过在服务器上运行的软件应用程序来实现负载均衡的。这些软件可以是开源的&#xff0c;如Nginx、HAProxy&#xff0c;也可以是商业产品。 工作原理&#xff1a; 运行环境&#xff1a; 软件负载均衡器通常运行在标准的物理服务器或虚拟机上…

使用死信队列(Dead Letter Exchange, DLX)实现延迟队列功能

在 Spring Boot 项目中整合 RabbitMQ 并使用死信队列&#xff08;Dead Letter Exchange, DLX&#xff09;实现延迟队列功能&#xff0c;可以通过配置 RabbitMQ 的交换机、队列和绑定关系来实现。以下是一个完整的示例&#xff0c;展示如何在 Spring Boot 项目中使用死信队列实现…

tensorflow-dataset 内网下载 指定目录

内网下载报错 解决办法是设置环境变量&#xff0c;指向你的代理服务器TFDS_HTTP_PROXYhttp://xxx、TFDS_HTTPS_PROXYhttp://xxx。 留意到&#xff0c;赋值的是你的代理服务器&#xff0c;且最好协议都使用http(即使TFDS_HTTPS_PROXY也要使用http协议连服务器)。如果不这么做&a…

zookeeper向管控平台上报状态

问题 在你的场景中&#xff0c;由于 Django 应用启动了 4 个 uWSGI 进程&#xff0c;每个进程都会创建一个节点并上报状态&#xff0c;因此出现了 4 次状态上报的情况。这在大多数情况下是不合理的&#xff0c;尤其是在你只期望应用上报一次状态时。 要解决这个问题并优雅地进…

医学数据分析实训 项目十 基于深度残差神经网络的皮肤癌检测

文章目录 综合实践三 基于深度残差神经网络的皮肤癌检测实现步骤1&#xff1a;图像数据预处理实现步骤2&#xff1a;模型构建实现步骤3&#xff1a;性能度量提交要求 1 基于深度残差神经网络的皮肤癌检测代码2 结果分析 综合实践三 基于深度残差神经网络的皮肤癌检测 皮肤镜图…