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

yizhihongxing

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应用服务器之tomcat会话复制集群配置的示例详解

    Java应用服务器之tomcat会话复制集群配置的示例详解 什么是tomcat会话复制集群 在高并发场景下,单台服务器很难完成大量请求的处理,因此很多企业都会将多台服务器组成一个集群,通过负载均衡的方式来分摊请求负载。但是这时候就会遇到一个问题,即如何保证用户在不同服务器之间的会话数据共享。这就需要采用会话复制集群技术,即将用户在一台服务器上的会话数据复制到…

    Java 2023年6月16日
    00
  • Java实现的求逆矩阵算法示例

    Java实现的求逆矩阵算法示例 什么是逆矩阵 矩阵A的逆矩阵记为A-1,它是一个与A相乘后得到单位矩阵的矩阵。在一般的情况下,只有方阵才有逆矩阵。 矩阵求逆算法 对于一个n阶方阵A,它的行列式为det(A)。 如果det(A)不等于0,则A可逆,它的逆矩阵B为: B = 1/det(A) * adj(A) 其中,adj(A)是A的伴随矩阵,它是由矩阵A的每个…

    Java 2023年5月19日
    00
  • 应用程序类加载器的作用是什么?

    应用程序类加载器的作用: Java应用程序在运行时,需要加载大量的类,这些类通常是由JDK自带的类库,以及我们自己编写的类组成的。为了保证程序可以正常运行,Java虚拟机需要通过类加载器来将这些类加载到内存中。而应用程序类加载器就是其中一种类加载器,其主要作用是从特定路径加载class文件到内存中,是类加载器中最常用的一种。 使用攻略: 首先需要了解应用程序…

    Java 2023年5月10日
    00
  • 深入解析Java编程中方法的参数传递

    深入解析Java编程中方法的参数传递 在Java编程中,方法是我们进行代码模块化的基本单位,而方法的参数传递是Java编程中比较基础但也比较重要的概念之一。本文将从以下几个方面深入解析Java编程中的方法参数传递。 Java方法参数是按值传递还是按引用传递? 这是一个比较基础的问题。实际上,在Java中,方法参数是按值传递的,而不是传递引用。 所谓“按值传递…

    Java 2023年5月26日
    00
  • JavaIO BufferedReader和BufferedWriter使用及说明

    JavaIO BufferedReader和BufferedWriter使用及说明 在Java中,读写文件是非常频繁的操作。BufferedReader和BufferedWriter是常用的文件读写工具类。本文将详细介绍这两个工具类的使用方法及说明。 BufferedReader BufferedReader是一个用来读取字符流的缓冲区。它以一个字符输入流作…

    Java 2023年5月20日
    00
  • JAVA中数组插入与删除指定元素的实例代码

    下面是针对“JAVA中数组插入与删除指定元素的实例代码”的完整攻略: 一、JAVA数组插入指定元素 在JAVA中,数组的长度是固定的,所以如果需要在数组中插入元素,我们必须新建一个长度为原数组长度+1的新数组,并将原数组中的元素复制到新数组中,在新数组中插入指定元素。 以下是一个示例代码,用于将指定元素插入到数组的指定位置: public class Arr…

    Java 2023年5月26日
    00
  • springMVC实现文件上传和下载

    下面我将详细讲解 Spring MVC 实现文件上传和下载的完整攻略。 文件上传 准备工作 在 Spring MVC 中,文件上传需要使用 MultipartResolver 接口来进行解析。常用的实现类有两种,分别是: StandardServletMultipartResolver:使用 Servlet API(3.0)中的 Part 接口进行文件上传解…

    Java 2023年6月15日
    00
  • Service Temporarily Unavailable的503错误是怎么回事?

    首先我们需要了解,我们在浏览网页时,当我们向服务器请求数据时,如果服务器无法正常处理这些请求,我们就会遇到各种各样的错误码,其中包括503错误。 什么是503错误?503错误是服务器向客户端返回的一种错误码,表示当前服务不可用,可能是暂时的或永久的。它的HTTP状态码为503,通常会伴随着“Service Temporarily Unavailable”的提…

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