java多线程之wait(),notify(),notifyAll()的详解分析

Java多线程之wait(), notify(), notifyAll()的详解分析

在Java多线程编程中,wait(), notify(), notifyAll()是非常重要的方法。这三个方法都是用于线程间的协作,可以让线程在合适的时候等待或唤醒其他线程,实现高效的资源共享和数据交换。本文将详细介绍wait(), notify(), notifyAll()的概念、作用和使用方法,并提供两个示例说明。

wait()

wait()方法是Object类中定义的方法,用于让当前线程进入等待状态,直到收到其他线程的notify()或notifyAll()通知后再继续执行。wait()方法通常和synchronized关键字一起使用,以保证同步和互斥的效果。当线程执行wait()方法时,它会释放占有的锁对象,让其他线程可以访问共享资源。当其他线程改变资源状态并调用notify()或notifyAll()方法时,处于等待状态的线程将被唤醒,重新竞争锁,并继续执行。

wait()方法有三个重载方法:

  • wait(): 让当前线程无限期等待,直到其他线程调用notify()或notifyAll()方法唤醒它。
  • wait(long timeout): 让当前线程等待一定时间,直到超时或收到其他线程的notify()或notifyAll()通知唤醒它。
  • wait(long timeout, int nanos): 和wait(long timeout)类似,只是更精细地定义了等待时间。

wait()方法的使用常见模式如下所示:

synchronized (object) {
    while (condition does not hold) {
        object.wait();
    }
    // take action based on condition holding
}

其中,object是一个共享对象,condition是一个布尔表达式,用于描述等待条件是否成立。执行wait()方法时,先获取Object对象的锁对象,然后判断条件是否成立。如果不成立,则调用wait()方法让当前线程进入等待状态,并释放Object的锁对象,让其他线程可以获得该锁对象并修改共享变量。当其他线程更新共享变量并符合等待条件时,调用notify()或notifyAll()方法唤醒处于等待状态的线程,并重新竞争Object的锁对象,继续执行。

notify()

notify()方法也是Object类中定义的方法,用于唤醒处于wait()方法等待状态的一个线程,并通知它有可能可以重新竞争锁对象。notify()方法一般用于在同步代码块内部,唤醒等待线程并让它重新竞争所属对象的锁。如果有多个等待线程,notify()方法只随机唤醒其中的一个线程,并不保证唤醒的线程是最优先等待的线程。

notify()方法一般的使用模式如下:

synchronized (object) {
    // make some change to shared variables
    object.notify();
}

其中,object是共享对象,调用notify()方法表示唤醒了处于object上wait()状态下的某一个线程并让它重新竞争锁。

notifyAll()

notifyAll()方法和notify()方法类似,也是用于唤醒处于wait()状态的线程,并让它们重新竞争锁对象。不同点是,notifyAll()方法会唤醒所有处于当前对象等待队列上的线程,让它们可以重新竞争所属对象的锁。如果多个线程等待同一个共享对象,notifyAll()方法将唤醒所有线程,并让它们重新竞争对象锁。

notifyAll()方法一般的使用模式如下:

synchronized (object) {
    // make some change to shared variables
    object.notifyAll();
}

示例说明一

代码如下:

public class WaitNotifyExample {
    public static void main(String[] args) {
        final Processor processor = new Processor();
        Thread producerThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    processor.produce();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread consumerThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    processor.consume();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        producerThread.start();
        consumerThread.start();
    }
}

class Processor {
    public void produce() throws InterruptedException {
        synchronized (this) {
            System.out.println("Producer thread running...");
            wait();
            System.out.println("Producer thread resumed.");
        }
    }

    public void consume() throws InterruptedException {
        Thread.sleep(1000); // 模拟其他耗时操作
        Scanner scanner = new Scanner(System.in);
        synchronized (this) {
            System.out.println("Waiting for return key pressed...");
            scanner.nextLine();
            notify();
            Thread.sleep(5000); // 模拟其他耗时操作
        }
    }
}

在上面的代码中,我们定义了一个Processor类,它有两个方法produce()和consume()。produce()方法会让线程进入等待状态,并等待consume()方法的唤醒通知。consume()方法则会让线程进行一些耗时操作(模拟其他线程访问共享变量并对其进行修改),然后等待用户的键盘输入。当用户按下回车键时,consume()方法调用notify()方法唤醒处于等待状态的线程并输出"notify() called",然后进行一些其他的耗时操作(模拟其他线程访问共享变量并对其进行修改)。在主线程中,我们创建了两个线程,分别运行producerThread和consumerThread,并启动它们。运行程序后,输出如下:

Producer thread running...
Waiting for return key pressed...
notify() called
Producer thread resumed.

我们可以看到,producerThread线程进入了等待状态,直到consumerThread线程调用notify()方法,唤醒了producerThread线程并输出"notify() called",producerThread线程才停止等待,继续执行。

示例说明二

代码如下:

public class SecondWaitNotifyExample {
    private static Object lock = new Object();

    private static void log(String msg) {
        System.out.println(Thread.currentThread().getName() + ": " + msg);
    }

    public static void main(String[] args) {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    log("Thread-1 waiting...");
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    log("Thread-1 notified.");
                }
            }
        }, "Thread-1");
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    log("Thread-2 waiting...");
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    log("Thread-2 notified.");
                }
            }
        }, "Thread-2");
        Thread thread3 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    log("Thread-3 notifying...");
                    lock.notifyAll();
                }
            }
        }, "Thread-3");
        thread1.start();
        thread2.start();
        try {
            Thread.sleep(1000); // 暂停1秒,确保线程1和线程2都处于等待状态
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread3.start();
    }
}

在上面的代码中,我们定义了三个线程,分别为Thread-1、Thread-2和Thread-3。Thread-1和Thread-2作为等待线程,在lock对象上等待被其他线程唤醒;Thread-3作为通知线程,调用lock对象的notifyAll()方法唤醒等待在lock对象上的所有线程。在主线程中,我们启动线程1和线程2,并暂停1秒等待线程1和线程2都处于等待状态,然后启动线程3。

运行程序后,输出如下:

Thread-1: Thread-1 waiting...
Thread-2: Thread-2 waiting...
Thread-3: Thread-3 notifying...
Thread-1: Thread-1 notified.
Thread-2: Thread-2 notified.

我们可以看到,在Thread-3调用lock对象的notifyAll()方法后,两个等待线程Thread-1和Thread-2都被唤醒,并输出对应的日志。这是因为notifyAll()方法唤醒了所有等待线程,让它们重新竞争lock对象的锁。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java多线程之wait(),notify(),notifyAll()的详解分析 - Python技术站

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

相关文章

  • Java之Rsync并发迁移数据并校验详解

    Java之Rsync并发迁移数据并校验详解 本攻略主要介绍如何使用Java语言进行Rsync并发迁移数据并校验。 准备工作 在开始使用Java进行Rsync并发迁移数据并校验之前,我们需要在本地安装Rsync工具,并确保Java可以执行Shell命令。同时,我们还需要导入以下第三方库: <dependency> <groupId>ne…

    多线程 2023年5月16日
    00
  • php curl批处理实现可控并发异步操作示例

    下面是“php curl批处理实现可控并发异步操作示例”的完整攻略。 1. 准备工作 在开始之前,需要确保系统已经安装了curl扩展。可以通过以下命令来检查: php -m | grep curl 如果输出了curl,说明扩展已经安装成功。 2. 单个请求示例 首先来看一个简单的单个请求示例。代码如下: // 初始化curl $ch = curl_init(…

    多线程 2023年5月16日
    00
  • Java创建并运行线程的方法

    Java创建并运行线程的方法 在Java中,线程是一个非常重要的概念。线程可以让我们以一种非阻塞的方式来处理并发性问题,这使得Java变得非常适合于开发高性能、高并发的应用程序。本文将详细介绍Java创建并运行线程的方法。 Java创建线程的方法 在Java中,有两种方法来创建线程:继承Thread类,或者实现Runnable接口。以下是两种方法的示例代码:…

    多线程 2023年5月16日
    00
  • Nodejs高并发原理示例详解

    接下来我将详细讲解“Node.js高并发原理示例详解”的完整攻略。 Node.js高并发原理示例详解 什么是Node.js Node.js 是一个开源、跨平台的 JavaScript 运行环境,它允许我们使用 JavaScript 来编写后端服务器应用程序。它是建立在 Chrome V8 引擎的基础之上,利用它提供的非阻塞 I/O 和事件驱动模型,在处理大量…

    多线程 2023年5月17日
    00
  • C#多线程Thread使用示例详解

    下面我将详细讲解“C#多线程Thread使用示例详解”的完整攻略。 C#多线程Thread使用示例详解 什么是多线程? 在计算机里,线程是一个可执行的代码片段。我们可以将线程视为一堆计算机程序指令。一个程序可以同时运行多个线程。多线程技术可以让计算机同时处理多项任务,从而更加高效。 如何使用多线程? 在C#中,可以使用Thread类来实现多线程技术。具体使用…

    多线程 2023年5月17日
    00
  • Nodejs实战心得之eventproxy模块控制并发

    Node.js实战心得之eventproxy模块控制并发 什么是eventproxy模块 eventproxy模块是Node.js中一个流行的第三方模块,用于控制异步并发。它通过定义事件与处理定制逻辑来解决异步嵌套问题,提供更好的可读性和可维护性。 使用eventproxy模块,可以避免回调函数嵌套过深,提高代码的可阅读性,同时也避免了异步操作中的“回调地狱…

    多线程 2023年5月16日
    00
  • python实现多线程行情抓取工具的方法

    以下是详细讲解“Python实现多线程行情抓取工具的方法”的完整攻略。 目录 需求说明 方案设计 操作步骤 示例说明 总结 需求说明 我们需要编写一个Python程序,能够从多个行情网站上抓取指定股票代码或名称的实时行情数据,并将其保存到本地文件。为了提高效率,我们需要使用多线程技术,同时抓取多个行情网站的数据。 方案设计 技术选型 为了实现多线程数据抓取,…

    多线程 2023年5月16日
    00
  • Java创建多线程异步执行实现代码解析

    Java创建多线程异步执行是很常见的开发需求,在实际开发过程中也经常用到,本篇文章将细致地讲解如何实现这一功能,包括创建多线程的方式、线程的基础操作、如何使用Java的Concurrent包以及线程安全的问题等问题。 1. 创建多线程 Java中创建多线程的方式有很多,这里主要介绍两种方式。 1.1 继承Thread类 第一种方式就是继承Thread类,并重…

    多线程 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部