Java如何正确的使用wait-notify方法你知道吗

当多个线程可以共同访问同一资源时,为避免出现竞态条件,Java 提供了 wait-notify 方法。wait-notify 是 Object 类的两个方法,需要在同步代码块内被调用。wait 方法会使调用线程阻塞,直到另一个线程调用 notify 或 notifyAll 方法唤醒该线程。在该过程中,线程会释放锁。notify 方法则会随机唤醒等待中的一个线程(如果存在多个线程在等待同一个对象,则不能保证唤醒哪一个线程),notifyAll 则会唤醒所有等待线程。

下面是 wait-notify 方法的使用原则:

  1. wait 和 notify 方法只能在同步代码块内调用,并且必须通过同一对象的锁来调用。
  2. 在wait-notify使用过程中,必须加上synchronized,保证操作的原子性,防止数据冲突。
  3. 线程只有获得锁才可以进入wait状态或被唤醒,否则IllegalMonitorStateException。
  4. wait方法调用前必须先获取对象锁,否则抛出IllegalMonitorStateException异常。
  5. notify方法调用后会立即释放锁,而不是等待被唤醒的线程执行完才释放锁。

下面是一个示例,说明如何在Java中使用 wait-notify 方法:

public class ConsumerProducerExample {
    public static void main(String[] args) {
        //声明一个List作为缓冲器
        List<Integer> buffer = new ArrayList<>();
        //创建一个锁
        Object lock = new Object();
        //创建一个生产者
        Runnable producer = new Producer(buffer, lock);
        //创建一个消费者
        Runnable consumer = new Consumer(buffer, lock);
        //创建线程并启动
        new Thread(producer).start();
        new Thread(consumer).start();
    }
}

class Producer implements Runnable {
    private final List<Integer> buffer;
    private final Object lock;

    public Producer(List<Integer> buffer, Object lock) {
        this.buffer = buffer;
        this.lock = lock;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            synchronized (lock) {
                //如果缓冲器已满,生产者线程等待
                while (buffer.size() >= 1) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //将生产的元素添加到缓冲器
                buffer.add(i);
                System.out.println("Producer produced " + i);
                //唤醒消费者线程
                lock.notify();
            }
        }
    }
}

class Consumer implements Runnable {
    private final List<Integer> buffer;
    private final Object lock;

    public Consumer(List<Integer> buffer, Object lock) {
        this.buffer = buffer;
        this.lock = lock;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            synchronized (lock) {
                //如果缓冲器为空,消费者线程等待
                while (buffer.size() <= 0) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //从缓冲器中取出元素
                int num = buffer.remove(0);
                System.out.println("Consumer consumed " + num);
                //唤醒生产者线程
                lock.notify();
            }
        }
    }
}

在这个示例中,一个生产者线程和一个消费者线程共享一个缓冲器。生产者生产元素,并将它们添加到缓冲器中。一旦缓冲器已满,生产者线程调用 wait 方法等待。消费者从缓冲器中取出元素并消费,如果缓冲器已空,那么消费者线程调用 wait 方法等待。生产者和消费者通过锁和 wait-notify 机制彼此协作,共享缓冲器。

还有一个示例:

public class WaitNotifyExample {
    public void doWait() {
        synchronized (this) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void doNotify() {
        synchronized (this) {
            this.notify();
        }
    }
}

在这个示例中,doWait 方法使调用线程进入等待状态,直到另一个线程调用与该对象关联的 doNotify 方法唤醒该线程。这两个方法都是同步的,因此需要在同步块内部调用它们。

总之,wait-notify 方法是Java中管理线程间通信的重要方式之一。当多个线程可以共同访问共享资源时,wait-notify 可以使线程协同工作,避免竞态条件。在使用 wait-notify 机制时,需要注意同步代码块以及获得锁的顺序,使其尽可能地符合 Java 的线程安全规定。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java如何正确的使用wait-notify方法你知道吗 - Python技术站

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

相关文章

  • mybatis 实体类字段大小写问题 字段获取不到值的解决

    问题背景:在使用 MyBatis 进行数据查询时,有时会遇到实体类字段大小写问题,导致查询结果为空,需要解决该问题。 解决思路:针对实体类字段大小写问题,我们可以使用 MyBatis 提供的一些功能进行解决,包括在 SQL 映射文件中配置 resultMap、使用@Result注解或通过配置全局配置文件等方法。 具体步骤如下: 配置resultMap 在 S…

    Java 2023年5月26日
    00
  • 采集教程及采集分页设置问题

    下面是详细的采集教程及采集分页设置问题的完整攻略。 采集教程 什么是采集 采集是指从一个或多个网站上自动爬取(提取)数据的技术,是一种自动化的数据采集方法。 如何进行采集 进行采集需要用到一些工具,常用的工具有Python爬虫框架Scrapy、PHP采集工具PHP Simple HTML DOM Parser等。 其中,Scrapy是一款强大的Python爬…

    Java 2023年6月16日
    00
  • java过滤特殊字符操作(xss攻击解决方案)

    关于Java过滤特殊字符操作和XSS攻击解决方案,我将介绍以下的内容: 什么是XSS攻击和其危害 Java过滤特殊字符的两种方式 防止XSS攻击的解决方案 两个示例说明Java过滤特殊字符和防止XSS攻击的实现 1.什么是XSS攻击和其危害 XSS指的是CSS(Cascading Sytle Sheets)注入攻击,其中注入的JavaScript脚本需要网站…

    Java 2023年5月27日
    00
  • 一文带你了解Java排序算法

    一文带你了解Java排序算法 在计算机科学中,排序算法是一种将一组数据按照特定规则进行排列的过程。Java中提供了多种排序算法实现,本文将为您介绍常见的排序算法及其实现方式。 冒泡排序 冒泡排序是一种基本的排序算法,通过重复遍历要排序的列表来比较相邻的两个元素,如果顺序错误,则进行交换,直到没有任何交换发生为止。 public static void bub…

    Java 2023年5月19日
    00
  • java对象和json的来回转换知识点总结

    下面是详细讲解“Java对象和JSON的来回转换知识点总结”的完整攻略。 什么是JSON JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,常用于网络传输数据。它基于JavaScript语法的子集,但是可以被许多其他编程语言解析和生成。JSON格式的数据是一种名值对的集合,其中包含数组和对象。 Java对象和JSON…

    Java 2023年5月26日
    00
  • IIS6 和Tomcat5 的整合

    IIS6 和 Tomcat5 的整合,我们可以通过在 IIS6 中安装 Tomcat 的扩展程序来实现。这个扩展程序可以使 IIS6 和 Tomcat5 之间建立一个联杆使得两者能够进行通信。 以下是整合的步骤: 安装 Tomcat Connector 下载 Tomcat Connector ,一般都是apache-tomcat-connectors-1.2…

    Java 2023年5月20日
    00
  • JavaSpringBoot报错“TransactionSystemException”的原因和处理方法

    当使用Java的Spring Boot框架时,可能会遇到“TransactionSystemException”错误。这个错误通常是由以下原因之一引起的: 事务管理器配置错误:如果事务管理器配置错误,则可能会出现此错误。在这种情况下,需要检查事务管理器的配置并进行必要的更改。 事务注解使用错误:如果事务注解使用错误,则可能会出现此错误。在这种情况下,需要检查…

    Java 2023年5月5日
    00
  • JavaWeb HttpServletResponse对象及常用方法

    下面就来为你详细讲解“JavaWeb HttpServletResponse对象及常用方法”的完整攻略。 一、什么是HttpServletResponse对象 在JavaWeb开发中,HttpServletResponse对象代表服务器响应给客户端的HTTP应答。它是javax.servlet.http.HttpServlet类的子类,提供了一系列的方法来设…

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