zoukankan      html  css  js  c++  java
  • 如何在 Java 中正确使用 wait, notify 和 notifyAll?

    简介

        wait,notify,notifyAll,都是属于object对象提供的方法,但在实际工作中怎么使用这几个方法,确是很多程序员清楚,不够明白,在群里问,有人说,哪个线程想wait,就用

     需等待线程.wait(),就跟Thread.sleep()一样,唤醒也一样,这样显然是不对的。

       在 Java 中可以用 wait、notify 和 notifyAll 来实现线程间的通信。。举个例子,如果你的Java程序中有两个线程——即生产者和消费者,那么生产者可以通知消费者,让消费者开始消耗数据,因为队列缓 冲区中有内容待消费(不为空)。相应的,消费者可以通知生产者可以开始生成更多的数据,因为当它消耗掉某些数据后缓冲区不再为满。

     1、废话不多说,直接看demo吧

    package hello.wait_notify;
    
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Random;
    import java.util.concurrent.ConcurrentLinkedQueue;
    
    /**
     * Created by jacky on 2017/3/25 0025.
     */
    public class Waint_Notify {
        
            public static void main(String args[])
            {
                ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue();
                int maxSize = 10;
                Thread producer = new Producer(queue, maxSize, "PRODUCER");
                Thread consumer = new Consumer(queue, maxSize, "CONSUMER");
                producer.start();
                consumer.start();
    
            }
    
    
       static class Producer extends Thread {
            private ConcurrentLinkedQueue queue;
            private int maxSize;
    
            public Producer(ConcurrentLinkedQueue queue, int maxSize, String name) {
                super(name);
                this.queue = queue;
                this.maxSize = maxSize;
            }
    
            @Override
            public void run() {
                while (true) {
                    synchronized (queue) {
                        while (queue.size() == maxSize) {
                            try {
                                System.out.println("队列中已经满了,等待消费者消费!");
                                queue.wait();
                            } catch (Exception ex) {
                                ex.printStackTrace();
                            }
                        }
                        Random random = new Random();
                        int i = random.nextInt();
                        System.out.println("Producing value : " + i);
                        queue.add(i);
                        queue.notifyAll();
                    }
                }
            }
        }
    
       static class Consumer extends Thread {
            private ConcurrentLinkedQueue queue;
            private int maxSize;
    
            public Consumer(ConcurrentLinkedQueue queue, int maxSize, String name) {
                super(name);
                this.queue = queue;
                this.maxSize = maxSize;
            }
    
            @Override
            public void run() {
                while (true) {
                    synchronized (queue) {
                        while (queue.isEmpty()) {
                            System.out.println("队列已经空了,等待生产者放数据" );
                            try {
                                queue.wait();
                            } catch (Exception ex) {
                                ex.printStackTrace();
                            }
                        }
                        System.out.println("Consuming value : " + queue.remove());
                        queue.notifyAll();
                    }
                }
            }
        }
    }

    2、结果

    3、总结

    1. 你可以使用wait和notify函数来实现线程间通信。你可以用它们来实现多线程(>3)之间的通信。

    2. 永远在synchronized的函数里使用wait、notify和notifyAll,不然Java虚拟机会生成 IllegalMonitorStateException。

    3. 永远在while循环里而不是if语句下使用wait。这样,循环会在线程睡眠前后都检查wait的条件,并在条件实际上并未改变的情况下处理唤醒通知。

    4. 永远在多线程间共享的对象(在生产者消费者模型里即缓冲区队列)上使用wait。

    5. 基于前文提及的理由,更倾向用 notifyAll(),而不是 notify()。

  • 相关阅读:
    jquery 中 $.map 的使用方法
    数据库 'MessageManage' 的事务日志已满。若要查明无法重用日志中的空间的原因,请参阅 sys.databases 中的 log_reuse_wait_desc 列。
    Post提交
    MD5加密、时间戳转换、base64算法加密、解密
    C#中timer类的用法
    软件项目版本号的命名规则及格式
    SQL Server数据库脚本备份与还原
    C# Out,Ref 学习总结
    在线工具
    构造和析构 的顺序
  • 原文地址:https://www.cnblogs.com/520playboy/p/6616493.html
Copyright © 2011-2022 走看看