如何在 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()。

posted @ 2017-03-25 11:06  坏~牧羊人  阅读(641)  评论(0编辑  收藏  举报