Java中的wait、notify和notifyAll,多线程中经常会用到这些保留关键字,但在实际开发中往往没有被大家重视。本文介绍了这些关键字的用法。在Java中,wait、notify和notifyAll可以用于线程间的通信。.例如,如果你的Java程序中有两个线程——一个生产者和一个消费者,那么生产者可以通知消费者开始消费数据,因为队列缓冲区中有东西要被消费(不是为null)。因此,消费者可以通知生产者它可以开始生产更多的数据,因为当它消费一些数据时缓冲区不再满了。我们可以使用wait()在特定条件下挂起线程。例如,在生产者-消费者模型中,当缓冲区满时生产者线程应该暂停运行,当缓冲区为空时消费者应该暂停。如果某些线程正在等待某些条件触发,您可以使用notify和notifyAll通知那些等待的线程在这些条件为真时重新启动。不同的是notify只通知一个线程,我们不知道哪个线程会收到通知,而notifyAll会通知所有等待的线程。换句话说,如果只有一个线程在等待信号量,则notify和notifyAll都会通知那个线程。但是如果有多个线程在等待这个信号量,那么notify只会通知其中一个,而其他线程不会收到任何通知,notifyAll会唤醒所有等待的线程。在本文中你将学习如何使用wait、notify、notifyAll实现线程间通信来解决生产者消费者问题。如果你想了解更多关于Java中多线程同步的知识,我强烈推荐阅读BrianGoetz的《Java Concurrency in Practice|Java 并发实践》。不读这本书,你的Java多线程之旅是不完整的!这是我最推荐给Java开发人员的书籍之一。如何使用Wait虽然wait和notify的概念很基础,而且也是Object类的函数,但是使用它们写代码并不简单。如果在面试中让应聘者手写代码,使用wait和notify来解决producerconsumer问题,我几乎可以肯定,他们中的大部分人都会一头雾水,或者犯一些错误,比如错误的使用了synchronized关键字地方,没有在正确的对象上使用等待,或者没有遵循规范的代码方法。说实话,对于不经常使用的程序员来说,这个问题确实很头疼。第一个问题是,我们如何在代码中使用wait()?因为wait()不是Thread类下的函数,所以我们不能使用Thread.call()。其实很多Java程序员都喜欢这样写,因为他们习惯使用Thread。sleep(),所以他们会尝试使用wait()来达到同样的目的,但是他们很快就会发现这并不能顺利解决问题。正确的方法是使用等待多个线程之间共享的对象。在生产者消费者问题中,这个共享对象就是缓冲队列。第二个问题,既然要在同步函数或对象中调用wait,那么应该同步哪个对象呢?答案是你要加锁的对象应该是synchronized的,也就是多线程共享的对象。在生产者消费者问题中,应该同步的是缓冲队列。(我觉得这里的英文原文有问题。。。本来句末不应该有问号的,不然没意义。。。)总是调用wait和notifyin循环(loop),而不是在If语句中现在你知道wait应该总是在synchronized的上下文中调用,并且在被多个线程共享的对象上,接下来要记住的是你应该总是在wait中调用while循环,而不是在if语句中。因为线程在一定条件下等待——在我们的例子中,“如果缓冲区队列已满,那么生产者线程应该等待”,你可以直观地写一个if语句。但是if语句有一些微妙的问题,导致你的线程即使不满足条件也会被错误唤醒。所以如果你在线程被唤醒后不使用while循环检查是否满足唤醒条件,你的程序可能会出错——比如生产者在缓冲区满的时候继续产生数据,或者缓冲区为空。当消费者开始小数据时。所以请记住,始终在while循环中使用wait而不是if语句!我会推荐阅读《Effective Java》,这是关于如何正确使用等待和通知的最佳参考。基于以上知识,下面是使用wait和notify函数的标准代码模板:。G。takeorputintoqueue}之前说过,在while循环中使用wait的目的是在线程被唤醒前后不断检查是否满足条件。如果条件没有改变,在调用wait之前notify的唤醒通知来了,那么这个线程就不能保证被唤醒,可能会造成死锁问题。Javawait(),notify(),notifyAll()示例下面我们提供一个使用wait和notify的示例程序。在这个程序中,我们使用了上面描述的一些代码约定。我们有两个线程,分别命名为PRODUCER(生产者)和CONSUMER(消费者),它们继承了Producer和Consumer类,Producer和Consumer都继承了Thread类。Producer和Consumer要实现的代码逻辑都在run()函数中。Main线程启动生产者和消费者线程,并声明一个LinkedList作为缓冲队列(在Java中,LinkedList实现了队列的接口)。生产者在***循环中不断向LinkedList中插入随机整数,直到LinkedList满为止。我们在while(queue.size==maxSize)循环语句中检查这个条件。请注意,在执行此检查条件之前,我们在队列对象上使用了synchronized关键字,因此在我们检查条件时其他线程无法更改队列。如果队列已满,PRODUCER线程会继续等待,直到CONSUMER线程消费完队列中的任意整数,并使用notify通知PRODUCER线程。在我们的示例中,wait和notify都用于同一个共享对象。importjava.util.LinkedList;importjava.util.Queue;importjava.util.Random;/***SimpleJavaprogramtodemonstrateHowtousewait,notifyandnotifyAll()*methodinJavabysolvingproducerconsumerproblem.**@authorJavinPaul*/publicclassProducerConsumerInJava{publicstaticvoidmain(Stringargs[]){System.out.println("HowtusewaitandnotifymethodinJava");System.out.println("SolvingProducerConsumperProblem");Queue
