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多线程回调方法实例解析

    Java多线程回调方法实例解析 什么是回调方法 在Java中,回调方法是指将一个方法作为参数传递给另一个方法,并在另一个方法执行后,调用传入的方法。这种方式可以让我们将一个方法的执行结果传递给另一个方法,从而实现代码的复用和解耦。 为什么要使用多线程回调方法 在多线程编程中,需要处理并发执行的任务。一个任务执行完成后,需要通知其他任务执行相关的代码,这时就需…

    多线程 2023年5月17日
    00
  • 基于线程、并发的基本概念(详解)

    基于线程、并发的基本概念(详解) 什么是线程和并发? 线程 线程是程序执行的一条路径,每个线程都是独立的,具有自己的栈空间和程序计数器。同一个程序中如果有多个线程,它们可以并发执行,即同时执行,换句话说,多线程可以用来实现程序的并发性。 并发 并发,指的是系统能够同时处理多个任务的能力。例如,多个线程在同时执行不同的任务,或者同一个线程在同时执行多个任务,都…

    多线程 2023年5月17日
    00
  • Java多线程的原子性,可见性,有序性你都了解吗

    当多个线程并发执行同一段代码时,有可能会出现线程安全问题。而Java多线程的原子性,可见性和有序性是解决这些线程安全问题的关键。 原子性:原子性指的是一个操作不可中断,要么全部执行成功,要么全部执行失败。Java的基本数据类型的读取和赋值都是具有原子性的。但当多个线程同时对同一个变量进行运算时,就需要考虑原子性的问题。 示例说明: public class …

    多线程 2023年5月16日
    00
  • Java Runnable和Thread实现多线程哪个更好你知道吗

    当我们需要在Java中使用多线程时,最常见的做法是实现Runnable接口或继承Thread类。那么如何选择Runnable和Thread之间的实现方式呢?本攻略将详细讲解这个问题。 一、Java多线程基础 Java多线程是利用线程来实现多任务处理的一种编程模式。线程就是独立的执行路径,线程的启动和停止都是由JVM来控制的。 在Java中,实现多线程主要有两…

    多线程 2023年5月17日
    00
  • android实现多线程断点续传功能

    Android实现多线程断点续传功能需要以下步骤: 在AndroidManifest.xml中添加网络读写权限,以便应用程序能够进行网络请求. <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:n…

    多线程 2023年5月16日
    00
  • C#多线程之任务的用法详解

    C#多线程之任务的用法详解 在C#中,线程是常用的处理并发的方式,而任务是一种更高级别的并发编程模式。任务可以让程序员更加方便地实现异步编程,能够更好地利用CPU资源,提高程序的效率。 任务的基本概念 任务是由.NET Framework 4.0引入的一种编程模式,可以用于构建异步、并行的应用程序。任务具有以下特点: 可以在多个线程之间自动地分布和调度; 可…

    多线程 2023年5月16日
    00
  • C/C++中线程基本概念与创建详解

    C/C++中线程基本概念与创建详解 什么是线程? 线程是进程中的一个执行单元,一个进程可以有多个线程,各个线程可以并行执行不同的任务,彼此之间相对独立。线程共享进程的地址空间,可以方便地相互通信。 线程的创建 在C/C++语言中,可以通过调用系统提供的API函数来创建线程。常见的API函数有: CreateThread():Windows系统下的线程创建AP…

    多线程 2023年5月17日
    00
  • C++ 线程(串行 并行 同步 异步)详解

    C++ 线程详解 C++ 中的线程是一种基于同步和异步的编程模型,可以帮助程序员更好地利用 CPU 和内存资源,提高程序性能。本篇文章将详细讲解C++ 线程的概念、分类以及用法。 线程概念 一个线程是程序执行中的单一线路,每个线程都有自己的指令计数器、栈空间和寄存器等,并同时访问共同的全局数据。C++ 中线程的作用和进程类似,一个进程包含多个线程,每个线程可…

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