JavaNotify:实现线程间通信的利器

Java是目前最流行的编程语言之一,其并发编程能力也是相当强大的。在多线程编程中,线程间的通信无疑是非常关键的。Java提供了多种方式来实现线程间通信,其中最常见的方式之一就是使用对象的wait()和notify()方法。这种方式不仅简单易用,而且在Java中广泛应用于各种场景下。

一、wait-notify机制的概述

wait-notify机制是Java中实现线程间通信的一种机制。它通过在不同的线程之间共享对象来实现线程间的通信。具体来说,某个线程调用对象的wait()方法后,会让该线程处于等待状态,并且该线程释放所持有的对象锁;而另一个线程调用该对象的notify()方法后,会使得等待中的线程被唤醒并且重新竞争对象锁。因此,wait-notify机制可以帮助我们更好地控制线程的执行。

二、wait-notify机制的使用

1. wait()方法

java.lang.Object提供了wait()方法,用于将当前的线程置入“睡眠”状态,且只有等待另一个线程来唤醒此线程。wait()方法常用于线程间交互/通信的场合,通常有线程A调用了对象的wait()方法进入等待状态,而线程B调用了相同对象的notify()或notifyAll()方法,使得该对象的等待线程重新进入可运行状态。


/**
 * wait方法
 */
public class WaitDemo implements Runnable{
    private static Object object = new Object();
    @Override
    public void run() {
        synchronized (object){
            try {
                System.out.println(Thread.currentThread().getName() + " wait开始..");
                object.wait();
                System.out.println(Thread.currentThread().getName() + " 被唤醒..");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        WaitDemo waitDemo1 = new WaitDemo();
        WaitDemo waitDemo2 = new WaitDemo();
        Thread thread1 = new Thread(waitDemo1, "线程1");
        Thread thread2 = new Thread(waitDemo2, "线程2");
        thread1.start();
        thread2.start();
        System.out.println("主线程睡眠2秒开始..");
        Thread.sleep(2000); //主线程睡眠3秒
        System.out.println("主线程睡眠2秒结束..");
        synchronized (object){
            object.notifyAll();
        }
        System.out.println("主线程唤醒等待线程结束..");
    }
}

注意事项:

  • wait方法必须使用在synchronized同步中。
  • wait方法会释放锁,而notity方法不会释放锁。
  • wait方法和notify,notifyAll方法不会自动释放锁。

2. notify()方法

java.lang.Object提供了notify()方法,唤醒一个因调用了wait()方法而处于阻塞状态的线程。


/**
 * notify方法
 */
public class NotifyDemo implements Runnable{
    private static Object object = new Object();
    @Override
    public void run() {
        synchronized (object){
            System.out.println(Thread.currentThread().getName() + " 进入等待状态..");
            try {
                object.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " 被唤醒..");
        }
    }

    public static void main(String[] args) {
        NotifyDemo notifyDemo = new NotifyDemo();
        Thread thread1 = new Thread(notifyDemo, "线程1");
        Thread thread2 = new Thread(notifyDemo, "线程2");
        thread1.start();
        thread2.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (object){
            object.notify(); //随机唤醒一个线程
            //object.notifyAll(); 唤醒所有线程
        }
        System.out.println("主线程唤醒所有线程结束..");
    }
}

三、wait-notify机制的注意事项

1. Wait和Notify的阻塞队列

线程在争取到锁之后,如果发现自己无法继续执行,就会释放锁,并进入该锁对象的等待队列(wait-set)中。在锁被释放的同时,该线程也进入到该锁的等待队列中,并且会挂起线程。当锁被另一个线程重新竞争并成功获取后,它就会唤醒该锁等待队列中的某个线程,唤醒的操作由notify或者notifyAll方法完成。

2. 避免因过多的notify()而导致の虚假唤醒(Spurious Wakeup)问题

由于操作系统底层的原因,某些情况下JVM会在没有notify()调用的情况下自动唤醒waiting线程。例如:CPU资源不足,只要有线程有等待状态结束了,它就会进行唤醒操作。

为了避免这种情况的发生,往往需要将在wait()的时候用while来判断条件,以保证线程在唤醒后,会重新判断条件并决定是否执行后续的工作。以下是一个示例代码:


/**
 * 避免虚假唤醒问题
 */
public class WaitNotifyDemo implements Runnable{
    private static final Object object = new Object();
    private static boolean flag;

    @Override
    public void run() {
        synchronized (object){
            while (!flag){
                try {
                    System.out.println(Thread.currentThread().getName() + "等待中..");
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + "被唤醒..");
        }
    }

    public static void main(String[] args) {
        WaitNotifyDemo waitNotifyDemo = new WaitNotifyDemo();
        Thread thread1 = new Thread(waitNotifyDemo, "线程1");
        Thread thread2 = new Thread(waitNotifyDemo, "线程2");
        thread1.start();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        synchronized (object){
            flag = true;
            System.out.println("flag = true,唤醒所有线程..");
            object.notifyAll();
        }
    }
}

总结

本文介绍了Java中实现线程间通信的利器——wait-notify机制。wait-notify机制通过在不同的线程之间共享对象来实现线程间的通信,使用起来简单易懂,适用于各种场景。然而在使用过程中,需注意wait-notify机制的细节和注意事项。我们通过编写示例代码,希望能帮助读者更好地理解wait-notify机制。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/295990.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-27 12:57
下一篇 2024-12-27 12:57

相关推荐

  • Python刷课:优化学习体验的利器

    Python刷课作为一种利用自动化技术优化学习体验的工具已经被广泛应用。它可以帮助用户自动登录、自动答题等,让用户在学习过程中可以更加专注于知识本身,提高效率,增加学习乐趣。 一、…

    编程 2025-04-29
  • lsw2u1:全能编程开发工程师的利器

    lsw2u1是一款多功能工具,可以为全能编程开发工程师提供便利的支持。本文将从多个方面对lsw2u1做详细阐述,并给出对应代码示例。 一、快速存取代码段 在日常开发中,我们总会使用…

    编程 2025-04-29
  • Python线程等待指南

    本文将从多个方面详细讲解Python线程等待的相关知识。 一、等待线程结束 在多线程编程中,经常需要等待线程执行完毕再进行下一步操作。可以使用join()方法实现等待线程执行完毕再…

    编程 2025-04-29
  • Python两个线程交替打印1到100

    这篇文章的主题是关于Python多线程的应用。我们将会通过实际的代码,学习如何使用Python两个线程交替打印1到100。 一、创建线程 在Python中,我们可以使用Thread…

    编程 2025-04-28
  • ROS线程发布消息异常解决方法

    针对ROS线程发布消息异常问题,我们可以从以下几个方面进行分析和解决。 一、检查ROS代码是否正确 首先,我们需要检查ROS代码是否正确。可能会出现的问题包括: 是否正确初始化RO…

    编程 2025-04-28
  • HBuilder2.0:一站式开发利器

    本文将从如下几个方面对HBuilder2.0进行详细阐述,帮助初学者快速了解并开始使用该工具: 一、简介 HBuilder2.0是一个跨平台的HTML5集成开发工具。它综合了编码、…

    编程 2025-04-28
  • Powersploit:安全评估与渗透测试的利器

    本文将重点介绍Powersploit,并给出相关的完整的代码示例,帮助安全人员更好地运用Powersploit进行安全评估和渗透测试。 一、Powersploit简介 Powers…

    编程 2025-04-28
  • JL Transaction – 实现分布式事务管理的利器

    本文将为大家介绍JL Transaction,这是一款可以实现分布式事务管理的开源事务框架,它可以帮助企业在分布式环境下有效地解决事务的一致性问题,从而保障系统的稳定性和可靠性。 …

    编程 2025-04-28
  • 全自动股票交易软件:实现自动交易赚取更多收益的利器

    全自动股票交易软件是一款能够帮助股票投资者实现自动交易,据此获取更多收益的利器。本文将从多个方面详细阐述该软件的特点、优点、使用方法及相关注意事项,以期帮助读者更好地了解和使用该软…

    编程 2025-04-27
  • Python线程池并发爬虫

    Python线程池并发爬虫是实现多线程爬取数据的常用技术之一,可以在一定程度上提高爬取效率和数据处理能力。本文将从多个方面对Python线程池并发爬虫做详细的阐述,包括线程池的实现…

    编程 2025-04-27

发表回复

登录后才能评论