如何在 Java 中正确使用 wait,notify 和 notifyAll

 我来答
影视后期制作学习
2017-05-26 · 知道合伙人教育行家
影视后期制作学习
知道合伙人教育行家
采纳数:258 获赞数:698
荣获北京智泽苑教育科技有限公司金牌教师称号。

向TA提问 私信TA
展开全部
有 爪哇 中间间要要 wait、notify 与 notifyAll

?我们要利要wait()来让111个线程有某些要求发载暂时结束运行。像,有制造者购买者模式中间间,制造者线程有缓充区都是是是满的时间,购买者有缓充区都是是是空的时

候,全要暂时结束运行。若某些线程有等某些要求触发,哪做哪些要求都是是是真时,您要要 notify 与 notifyAll

来公告哪些等中间间的线程重新办始运行。不同之处有于,notify 仅仅公告111个线程,并且我们不知道哪11个线程要收中间间公告,然而 notifyAll

要公告所有等中间间的线程。转言之,若有111个线程有等111个信号码灯,notify与notifyAll全要公告中间间这11个线程。但若多11个线程有等这11个信

号码灯,哪么notify光要公告中间间其中间间111个,而其他线程并不要收中间间任何公告,而notifyAll要呼唤所有等中间间的线程。

有这篇文章中间间您将要学中间间如何要 wait、notify 与 notifyAll 来实现线程间的通信,从而解决制造者购买者问答题。若您需要要更深入地学习爪哇中间间的多线程同步问答题,我强烈推荐阅读Brian Goetz所著的《爪哇 Concurrency in Practice | 爪哇 并发实践》,不读这本书您的 爪哇 多线程征程就不完整哦!这都是是是我最向爪哇办发者推荐的书之1。

如何要Wait

尽管关于wait与notify的概念很基础,她们也全都是是是Object类型的函数,但要她们来书编码却并不简单。若您有面试中间间让应聘者来手书编码,

要wait与notify解决制造者购买者问答题,我几乎要肯定他们中间间的大多数全要无所适从或犯发载1些问答题,像有问答题的位置要

synchronized 关键歌词,没有给准确的给象要wait,或没有遵循标准的编码技术。说实话,这11个问答题给于不常要她们的程序员来说确实令人感觉比较头疼。

第111个问答题就都是是是,我们如何有编码中间间要wait()呢?因都是是是wait()并不都是是是Thread类型发载的函数,我们并没有有要

Thread.call()。事实中间间很多爪哇程序员全喜欢这么书,因都是是是她们习惯了要Thread.sleep(),所以他们要尝试要wait()

来达成相同的目标,但很快他们就要发现这并没有有顺利解决问答题。准确的技术都是是是给有多线程间共享的哪11个Object来要wait。有制造者购买者问答题中间间,这

11个共享的Object就都是是是哪11个缓充区队列。

第二11个问答题都是是是,既然我们要有synchronized的函数或都是是是给象中间间调要wait,哪哪11个给象要让synchronized呢?答案都是是是,哪11个

您希望中间间锁的给象就要让synchronized,即哪11个有多11个线程间让共享的给象。有制造者购买者问答题中间间,要让synchronized的就都是是是哪11个

缓充区队列。(我觉得这中间间都是是是英文原文有问答题……本来哪11个句末就不要都是是是问号码不然不太通……)

永久有循环(loop)中间间调要 wait 与 notify,不都是是是有 If 语句

现有您知道wait要永久有让synchronized的背景发载与哪11个让多线程共享的给象中间间调要,发载111个1定要记录得的问答题就都是是是,您要永久有

while循环,而不都是是是if语句中间间调要wait。因都是是是线程都是是是有某些要求发载等的——有我们的例子中间间,即“若缓充区队列都是是是满的话,哪么制造者线程要等

待”,您要直觉就要书111个if语句。但if语句存有1些微妙的小问答题,致即使要求没有让满足,您的线程您也有要让问答题地呼唤。所以若您不有线程让唤

醒后再次要while循环查呼唤要求都是是是否让满足,您的程序就有要要出错——像有缓充区都是是是满的时间制造者继续生成数据,或缓充区都是是是空的时间购买者

办始小号码数据。所以记录得,永久有while循环而不都是是是if语句中间间要wait!我要推荐阅读《Effective 爪哇》,这都是是是关于如何准确要wait与notify的好的参考资料。

基于以中间间认知,发载面这11个都是是是要wait与notify函数的标准编码模板:

// The standard idiom for calling the wait method in 爪哇 synchronized (sharedObject) { while (condition) { sharedObject.wait(); // (Releases lock, and reacquires on wakeup) } // do action based upon condition e.g. take or put into queue }

就像我以前说的1样,有while循环中间间要wait的目标,都是是是有线程让呼唤的前后全持续查要求都是是是否让满足。若要求并未改变,wait让调要以前notify的呼唤公告就来了,哪么这11个线程并没有有保证让呼唤,有要要致死锁问答题。

爪哇 wait(), notify(), notifyAll() 范例

发载面我们提供111个要wait与notify的范例程序。有这11个程序中间间,我们要了中间间文所述的1些编码标准。我们有两11个线程,区别名都是是是

PRODUCER(制造者)与消费者(购买者),他们区别继承了了Producer与消费者类型,而Producer与

消费者全继承了Thread类型。Producer与消费者需要要实现的编码逻辑全有run()函数内。Main线程办始了制造者与购买

者线程,并声明了111个LinkedList作都是是是缓充区队列(有爪哇中间间,LinkedList实现了队列的接口)。制造者有无限循环中间间持续往

LinkedList中间间插入随机整数直中间间LinkedList满。我们有while(queue.size ==

maxSize)循环语句中间间查这11个要求。请注意中间间我们有做这11个查要求以前已经有队列给象中间间要了synchronized关键歌词,因而其他线程没有有有

我们查要求时改变这11个队列。若队列满了,哪么PRODUCER线程要有消费者线程耗掉队列中间间的任意111个整数,并要notify来公告

PRODUCER线程以前持续等。有我们的例子中间间,wait与notify全都是是是要有同111个共享给象中间间的。

import 爪哇.util.LinkedList; import 爪哇.util.Queue; import 爪哇.util.Random; /** * Simple 爪哇 program to demonstrate How to use wait, notify and notifyAll() * method in 爪哇 by solving producer 消费者 problem. * * @author Javin Paul */ public class Producer消费者In爪哇 { public static void main(String args[]) { System.out.println("How to use wait and notify method in 爪哇"); System.out.println("Solving Producer Consumper Problem"); Queue<Integer> buffer = new LinkedList<>(); int maxSize = 10; Thread producer = new Producer(buffer, maxSize, "PRODUCER"); Thread 消费者 = new 消费者(buffer, maxSize, "消费者"); producer.start(); 消费者.start(); } } /** * Producer Thread will keep producing values for 消费者 * to 消费者. It will use wait() method when Queue is full * and use notify() method to send notification to 消费者 * Thread. * * @author WINDOWS 8 * */ class Producer extends Thread { private Queue<Integer> queue; private int maxSize; public Producer(Queue<Integer> 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 is full, " + "Producer thread waiting for " + "消费者 to take something from queue"); 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(); } } } } /** * 消费者 Thread will 消费者 values form shared queue. * It will also use wait() method to wait if queue is * empty. It will also use notify method to send * notification to producer thread after consuming values * from queue. * * @author WINDOWS 8 * */ class 消费者 extends Thread { private Queue<Integer> queue; private int maxSize; public 消费者(Queue<Integer> 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("Queue is empty," + "消费者 thread is waiting" + " for producer thread to put something in queue"); try { queue.wait(); } catch (Exception ex) { ex.printStackTrace(); } } System.out.println("Consuming value : " + queue.remove()); queue.notifyAll(); } } } }

都是是是了更好地理解这11个程序,我建议您有debug模式中间间走这11个程序。1旦您有debug模式发载启动程序,它要结束有PRODUCER或

消费者线程中间间,取决于哪11个线程占领了CPU。因都是是是两11个线程全有wait()的要求,她们1定要结束,然后您就要走这11个程序然后看发生什么了

(很有要它就要输出我们以中间间展示的内容)。您也要要Eclipse中间间的Step into与Step over按钮来更好地理解多线程间发生的事情。

本文重点:

1. 您要要wait与notify函数来实现线程间通信。您要要她们来实现多线程(>3)之间的通信。

2. 永久有synchronized的函数或给象中间间要wait、notify与notifyAll,不然爪哇虚拟机要生成 IllegalMonitorStateException。

3. 永久有while循环中间间而不都是是是if语句发载要wait。这样,循环要有线程睡眠前后全查wait的要求,并有要求实际中间间并未改变的情况发载处理呼唤公告。

4. 永久有多线程间共享的给象(有制造者购买者模式中间间即缓充区队列)中间间要wait。

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

这都是是是关于爪哇中间间如何要wait,

notify与notifyAll的所有重点啦。您要有您知道自己要做什么的情况发载要这些函数,不然爪哇中间间有很多其他的要来解决同步问答题的方

案。像,若您需要要制造者购买者模式的话,您也要要BlockingQueue,它要帮您处理所有的线程安全问答题与流程控制。若您需要要某111个线

程等另111个线程做出反馈再继续运行,您也要要CycliBarr浏览器r或CountDownLatch。若您光都是是是需要保护某111个资源的话,您也可

以要Semaphore。
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
DoramiHe
2017-05-28 · 知道合伙人互联网行家
DoramiHe
知道合伙人互联网行家
采纳数:25332 获赞数:59543
2011年中山职业技术学院毕业,现担任毅衣公司京东小二

向TA提问 私信TA
展开全部
wait, notify 和 notifyAll,这些在多线程中被经常用到的保留关键字,在实际开发的时候很多时候却并没有被大家重视。本文对这些关键字的使用进行了描述。
在 Java 中可以用 wait、notify 和 notifyAll 来实现线程间的通信。。举个例子,如果你的Java程序中有两个线程——即生产者和消费者,那么生产者可以通知消费者,让消费者开始消耗数据,因为队列缓 冲区中有内容待消费(不为空)。相应的,消费者可以通知生产者可以开始生成更多的数据,因为当它消耗掉某些数据后缓冲区不再为满。
我们可以利用wait()来让一个线程在某些条件下暂停运行。例如,在生产者消费者模型中,生产者线程在缓冲区为满的时候,消费者在缓冲区为空的时 候,都应该暂停运行。如果某些线程在等待某些条件触发,那当那些条件为真时,你可以用 notify 和 notifyAll 来通知那些等待中的线程重新开始运行。不同之处在于,notify 仅仅通知一个线程,并且我们不知道哪个线程会收到通知,然而 notifyAll 会通知所有等待中的线程。换言之,如果只有一个线程在等待一个信号灯,notify和notifyAll都会通知到这个线程。但如果多个线程在等待这个信 号灯,那么notify只会通知到其中一个,而其它线程并不会收到任何通知,而notifyAll会唤醒所有等待中的线程。
在这篇文章中你将会学到如何使用 wait、notify 和 notifyAll 来实现线程间的通信,从而解决生产者消费者问题。如果你想要更深入地学习Java中的多线程同步问题,我强烈推荐阅读Brian Goetz所著的《Java Concurrency in Practice | Java 并发实践》,不读这本书你的 Java 多线程征程就不完整哦!这是我最向Java开发者推荐的书之一。
如何使用Wait
尽管关于wait和notify的概念很基础,它们也都是Object类的函数,但用它们来写代码却并不简单。如果你在面试中让应聘者来手写代码, 用wait和notify解决生产者消费者问题,我几乎可以肯定他们中的大多数都会无所适从或者犯下一些错误,例如在错误的地方使用 synchronized 关键词,没有对正确的对象使用wait,或者没有遵循规范的代码方法。说实话,这个问题对于不常使用它们的程序员来说确实令人感觉比较头疼。
第一个问题就是,我们怎么在代码里使用wait()呢?因为wait()并不是Thread类下的函数,我们并不能使用 Thread.call()。事实上很多Java程序员都喜欢这么写,因为它们习惯了使用Thread.sleep(),所以他们会试图使用wait() 来达成相同的目的,但很快他们就会发现这并不能顺利解决问题。正确的方法是对在多线程间共享的那个Object来使用wait。在生产者消费者问题中,这 个共享的Object就是那个缓冲区队列。
第二个问题是,既然我们应该在synchronized的函数或是对象里调用wait,那哪个对象应该被synchronized呢?答案是,那个 你希望上锁的对象就应该被synchronized,即那个在多个线程间被共享的对象。在生产者消费者问题中,应该被synchronized的就是那个 缓冲区队列。(我觉得这里是英文原文有问题……本来那个句末就不应该是问号不
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式