Given the difficulty of using wait and notify correctly, you should use the higher-level concurrency utilities instead [...] using wait and notify directly is like programming in "concurrency assembly language", as compared to the higher-level language provided by java.util.concurrent. There is seldom, if ever, reason to use wait and notify in new code.
# 2 楼答案
不是队列示例,但非常简单:)
class MyHouse {
private boolean pizzaArrived = false;
public void eatPizza(){
synchronized(this){
while(!pizzaArrived){
wait();
}
}
System.out.println("yumyum..");
}
public void pizzaGuy(){
synchronized(this){
this.pizzaArrived = true;
notifyAll();
}
}
}
static class Consumer extends Thread {
private Queue<Integer> queue;
private int maxSize;
public Consumer(Queue<Integer> queue, int maxSize, String name) {
super(name);
this.queue = queue;
this.maxSize = maxSize;
}
@Override
public void run() {
Random random = new Random();
while (true) {
synchronized (queue) {
if (queue.isEmpty()) {
System.out.println("Queue is empty," + "Consumer thread is waiting" + " for producer thread to put something in queue");
try {
queue.wait();
} catch (Exception ex) {
ex.printStackTrace();
}
}
System.out.println(" vvv Consuming value : " + queue.remove());
queue.notify();
}
sleepRandom();
}
}
}
UTIL方法:
public static void sleepRandom(){
Random random = new Random();
try {
Thread.sleep(random.nextInt(250));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
申请代码:
public static void main(String args[]) {
System.out.println("How to use wait and notify method in Java");
System.out.println("Solving Producer Consumper Problem");
Queue<Integer> buffer = new LinkedList<>();
int maxSize = 10;
Thread producer = new Producer(buffer, maxSize, "PRODUCER");
Thread consumer = new Consumer(buffer, maxSize, "CONSUMER");
producer.start();
consumer.start();
}
示例输出:
^^^ Producing value : 1268801606
vvv Consuming value : 1268801606
Queue is empty,Consumer thread is waiting for producer thread to put something in queue
^^^ Producing value : -191710046
vvv Consuming value : -191710046
^^^ Producing value : -1096119803
vvv Consuming value : -1096119803
^^^ Producing value : -1502054254
vvv Consuming value : -1502054254
Queue is empty,Consumer thread is waiting for producer thread to put something in queue
^^^ Producing value : 408960851
vvv Consuming value : 408960851
^^^ Producing value : 2140469519
vvv Consuming value : 65361724
^^^ Producing value : 1844915867
^^^ Producing value : 1551384069
^^^ Producing value : -2112162412
vvv Consuming value : -887946831
vvv Consuming value : 1427122528
^^^ Producing value : -181736500
^^^ Producing value : -1603239584
^^^ Producing value : 175404355
vvv Consuming value : 1356483172
^^^ Producing value : -1505603127
vvv Consuming value : 267333829
^^^ Producing value : 1986055041
Queue is full, Producer thread waiting for consumer to take something from queue
vvv Consuming value : -1289385327
^^^ Producing value : 58340504
vvv Consuming value : 1244183136
^^^ Producing value : 1582191907
Queue is full, Producer thread waiting for consumer to take something from queue
vvv Consuming value : 1401174346
^^^ Producing value : 1617821198
vvv Consuming value : -1827889861
vvv Consuming value : 2098088641
# 5 楼答案
范例
public class myThread extends Thread{
@override
public void run(){
while(true){
threadCondWait();// Circle waiting...
//bla bla bla bla
}
}
public synchronized void threadCondWait(){
while(myCondition){
wait();//Comminucate with notify()
}
}
}
public class myAnotherThread extends Thread{
@override
public void run(){
//Bla Bla bla
notify();//Trigger wait() Next Step
}
}
# 1 楼答案
即使你特别要求
wait()
和notify()
,我觉得这句话仍然很重要:Josh Bloch,有效Java第二版,第69项:与
wait
和notify
相比,更喜欢并发实用程序(强调his):# 2 楼答案
不是队列示例,但非常简单:)
一些要点:
1) 决不
始终使用while(条件),因为
while(!pizzaExists){ wait(); }
李>2)在调用wait/nofity之前,必须先保持锁(已同步)。线程还必须在唤醒之前获得锁
3)尽量避免在同步块中获取任何锁,尽量不要调用外来方法(您不知道它们在做什么的方法)。如果必须这样做,一定要采取措施避免僵局
4)小心使用notify()。坚持使用notifyAll()直到你知道你在做什么
5)最后,但并非最不重要的一点,阅读Java Concurrency in Practice
# 3 楼答案
wait()
和notify()
方法旨在提供一种机制,允许线程阻塞,直到满足特定条件为止。为此,我假设您想要编写一个阻塞队列实现,其中有一些固定大小的元素备份存储您必须做的第一件事是确定希望方法等待的条件。在这种情况下,您希望
put()
方法阻塞,直到存储中有可用空间为止,并且希望take()
方法阻塞,直到有一些元素返回为止关于必须使用wait和notify机制的方式,有几点需要注意
首先,您需要确保对
wait()
或notify()
的任何调用都在同步的代码区域内(在同一对象上同步wait()
和notify()
调用)。出现这种情况的原因(标准螺纹安全问题除外)是由于一种称为丢失信号的情况例如,当队列恰好已满时,线程可能会调用
put()
,然后检查条件,确定队列已满,但在它阻止另一个线程调度之前。然后,第二个线程take()
从队列中获取一个元素,并通知等待的线程队列不再满。但是,因为第一个线程已经检查了条件,所以在重新调度后,它将只调用wait()
,即使它可能会取得进展通过在共享对象上进行同步,可以确保不会发生此问题,因为在第一个线程实际阻塞之前,第二个线程的
take()
调用将无法进行其次,由于一个被称为虚假唤醒的问题,您需要将正在检查的条件放入while循环,而不是if语句。在这里,等待的线程有时可以在不调用
notify()
的情况下重新激活。将此检查放入while循环将确保如果出现虚假唤醒,将重新检查条件,并且线程将再次调用wait()
正如其他一些答案所提到的,Java1.5引入了一个新的并发库(在
java.util.concurrent
包中),该库旨在提供对等待/通知机制的更高级别抽象。使用这些新功能,您可以像这样重写原始示例:当然,如果您确实需要阻塞队列,那么应该使用BlockingQueue接口的实现
另外,对于像这样的东西,我强烈推荐Java Concurrency in Practice,因为它涵盖了您想要了解的关于并发相关问题和解决方案的所有内容
# 4 楼答案
该问题要求等待()+通知(),涉及队列(缓冲区)。首先想到的是使用缓冲区的生产者-消费者场景
我们系统的三个组成部分:
生产者线程: 生产者在缓冲区中插入值,直到缓冲区已满。 如果缓冲区已满,生产者调用wait()并进入等待阶段,直到消费者唤醒它
消费者线程: 使用者线程从缓冲区中移除值,直到缓冲区为空。 如果缓冲区为空,则使用者调用wait()方法并进入等待状态,直到生产者发送通知信号
UTIL方法:
申请代码:
示例输出:
# 5 楼答案
范例
# 6 楼答案
你看过这个吗
此外,我建议你远离在真实软件中玩这种东西。使用它很好,这样您就知道它是什么,但是并发性到处都有陷阱。如果您正在为其他人构建软件,最好使用更高级别的抽象和同步集合或JMS队列
至少我是这么做的。我不是并发专家,所以尽可能避免手动处理线程