Java中的notyfy()和notifyAll()的本质区别

Java多线程编程中,我们经常会用到wait()、notify()和notifyAll()方法,它们都属于Object类中用于锁的方法。其中notify()和notifyAll()方法都是用来唤醒等待线程的方法,但它们在本质上是有一定区别的。

一、notify()和notifyAll()方法的作用

notify()和notifyAll()都用于唤醒当前对象上等待的线程,使其进入就绪状态,以便争夺对象锁并执行。它们都必须在同步块或同步方法中被调用。

notify()方法会随机唤醒当前对象中等待的一个线程,如果当前对象中有多个线程等待,那么哪个线程被唤醒是不确定的。因此,notify()方法常用于“生产者-消费者”模型中,当生产者往队列中放入一个元素后,只需要唤醒一个消费者线程进行消费即可。

notifyAll()方法会唤醒当前对象中等待的所有线程,这些线程将被全部放入就绪状态,线程调度程序随后会从这些线程中选择一个作为下一个执行线程。因此,notifyAll()方法常用于同步操作完成后唤醒所有等待的线程。

二、notify()和notifyAll()方法的区别

notify()方法和notifyAll()方法的本质区别在于唤醒等待线程的方式不同。notify()方法仅仅是唤醒任意一个等待线程,而notifyAll()方法会唤醒所有等待线程。因此,notify()方法存在线程竞争的问题,可能会导致一些线程永远都无法被唤醒。而notifyAll()方法虽然效率较低,但它可以确保所有的等待线程都能够被唤醒。

示例一:

public class NotifyTest implements Runnable {
    public synchronized void run() {
        System.out.println(Thread.currentThread().getName() + " begin to wait...");
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " has been notified...");
    }

    public static void main(String[] args) throws InterruptedException {
        NotifyTest notifyTest = new NotifyTest();
        Thread thread1 = new Thread(notifyTest, "Thread1");
        Thread thread2 = new Thread(notifyTest, "Thread2");
        Thread thread3 = new Thread(notifyTest, "Thread3");
        thread1.start();
        thread2.start();
        thread3.start();
        Thread.sleep(1000L);
        synchronized (notifyTest) {
            notifyTest.notify();
        }
    }
}

运行结果:

Thread1 begin to wait...
Thread2 begin to wait...
Thread3 begin to wait...
Thread1 has been notified...

在上面的示例中,我们创建了三个线程(Thread1、Thread2、Thread3),它们都调用notifyTest对象的wait()方法进行等待,然后主线程通过notify()方法唤醒对象上的一个线程。运行结果显示,只有Thread1被唤醒了,而Thread2和Thread3还在等待中,说明notify()方法只会唤醒其中的一个等待线程。

示例二:

public class NotifyAllTest implements Runnable {
    public synchronized void run() {
        System.out.println(Thread.currentThread().getName() + " begin to wait...");
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " has been notified...");
    }

    public static void main(String[] args) throws InterruptedException {
        NotifyAllTest notifyAllTest = new NotifyAllTest();
        Thread thread1 = new Thread(notifyAllTest, "Thread1");
        Thread thread2 = new Thread(notifyAllTest, "Thread2");
        Thread thread3 = new Thread(notifyAllTest, "Thread3");
        thread1.start();
        thread2.start();
        thread3.start();
        Thread.sleep(1000L);
        synchronized (notifyAllTest) {
            notifyAllTest.notifyAll();
        }
    }
}

运行结果:

Thread1 begin to wait...
Thread3 begin to wait...
Thread2 begin to wait...
Thread2 has been notified...
Thread1 has been notified...
Thread3 has been notified...

在上面的示例中,我们创建了三个线程(Thread1、Thread2、Thread3),它们都调用notifyAllTest对象的wait()方法进行等待,然后主线程通过notifyAll()方法唤醒对象上的全部等待线程。运行结果显示,所有的等待线程都被唤醒了,且唤醒的顺序是不确定的。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java中的notyfy()和notifyAll()的本质区别 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • JAVA Future类的使用详解

    JAVA Future类的使用详解 什么是Future类? Java中的Future类用于描述一个异步计算的结果,它提供了检查计算是否完成、等待计算完成和获取计算结果的方法。 Future类的使用方法 创建Future对象 可以使用java.util.concurrent.Executors类中的线程池工厂方法创建一个ExecutorService线程池,然…

    Java 2023年5月26日
    00
  • Java使用C3P0数据源链接数据库

    使用C3P0数据源链接数据库是Java编程中常见的一个任务,下面我们来详细讲解如何完成这个任务。 安装C3P0 首先,为了使用C3P0数据源链接数据库,我们需要在项目中添加C3P0的jar包,具体步骤如下: 在 Maven 项目中,在 pom.xml 中添加以下依赖: <dependency> <groupId>com.mchange…

    Java 2023年5月19日
    00
  • Spring Security实现基于RBAC的权限表达式动态访问控制的操作方法

    下面是Spring Security实现基于RBAC的权限表达式动态访问控制的操作方法的完整攻略: 步骤一:初始化Spring Security 使用Spring Security提供的依赖,在pom.xml文件中配置以下依赖项: <dependency> <groupId>org.springframework.security&l…

    Java 2023年5月20日
    00
  • 老生常谈java数组中的常见异常

    讲解“老生常谈java数组中的常见异常”的完整攻略,可以按照以下步骤进行: 1. 数组越界异常(ArrayIndexOutOfBoundsException) 这个异常是在数组下标超过数组的长度时发生的异常,下标从0开始,数组长度是从1开始,因此我们需要通过下标加减一来判断是否存在这个下标。 int[] array = {1, 2, 3, 4, 5}; in…

    Java 2023年5月26日
    00
  • Java泛型的用法及T.class的获取过程解析

    Java泛型的用法及T.class的获取过程解析 什么是泛型 泛型是Java语言中的一个重要特性,它允许我们在类或方法中预先声明使用的类型,并在实例化时指定具体的类型,从而达到代码复用的效果。 例如,在传统的Java编程中,如果要编写一个通用的Stack类,可以存储各种类型的数据,可以这样写: public class Stack { private Obj…

    Java 2023年5月20日
    00
  • Java基本类型与byte数组之间相互转换方法

    请看下面的讲解。 Java基本类型与byte数组之间相互转换方法 在Java中,有时候我们需要将基本类型(如int、float等)转换成byte数组,或者将byte数组转换成基本类型。本文将提供两种方法来实现这种相互转换。 1. 使用Java的ByteBuffer类 Java的ByteBuffer类可以很方便地完成基本类型与byte数组的转换。 将基本类型转…

    Java 2023年5月26日
    00
  • jenkins安装及其配置笔记

    下面是详细讲解“Jenkins安装及其配置笔记”的完整攻略。 1. 安装Jenkins 1.1 环境准备 要安装Jenkins,首先需要确保满足以下环境要求: 安装了Java JDK 8或更高版本; 至少有1GB的可用内存; 至少有1GB的可用磁盘空间。 1.2 下载Jenkins 官网下载地址:https://jenkins.io/download/ 推荐…

    Java 2023年5月19日
    00
  • SpringBoot学习篇之@Valid与@Validated的区别

    下面是SpringBoot学习篇之@Valid与@Validated的区别的攻略。 一、@Valid和@Validated的作用 在SpringMVC中,@Valid和@Validated注解全部用于校验参数。使用它们可以大大简化代码和提高代码的可读性。 二、@Valid和@Validated的区别 @Valid是JSR-303/JSR-349规范中的注解,…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部