Java 为什么我的制作人-消费者计划被阻止?
我已经创建了自己的队列 Queue.javaJava 为什么我的制作人-消费者计划被阻止?,java,multithreading,producer-consumer,Java,Multithreading,Producer Consumer,我已经创建了自己的队列 Queue.java public class MyQueue { private int size; private Queue<String> q; public MyQueue(int size ,Queue<String> queue) { this.size = size; this.q = queue; } //getter and setter pub
public class MyQueue {
private int size;
private Queue<String> q;
public MyQueue(int size ,Queue<String> queue) {
this.size = size;
this.q = queue;
}
//getter and setter
public synchronized void putTail(String s) {
System.out.println(this.size); // It should print 0, 1,2
while (q.size() != size) {
try {
wait();
}
catch (InterruptedException e) {
}
}
Date d = new Date();
q.add(d.toString());
notifyAll();
}
}
MyTest.java
public class MyTest {
public static void main(String[] args) {
Queue q = new PriorityQueue<String>();
MyQueue mq = new MyQueue(3,q);
MyProducer p = new MyProducer(3,mq);
MyProducer p1 = new MyProducer(3,mq);
MyProducer p2 = new MyProducer(3,mq);
new Thread(p).start();
new Thread(p1).start();
new Thread(p2).start();
}
}
但它只打印0
为什么?
注:我只写了生产者代码,因为我还没有到达那里。因为
putTail()
是同步的
,三个线程中只有一个可以进入它。然后,该线程永远位于while(q.size()!=size)
循环中,而其他两个线程仍然无法进入该方法。问题在于MyQueue
类的putTail()
方法。在这个(当前对象)上调用wait()
,它永远不会被通知。然后线程将永远等待 问题是,所有3个线程都进入了wait()
,但从未通过notifyAll
您的代码有一个问题,它并没有真正成为阻塞队列。我希望阻塞队列可以执行以下操作:
队列的最大大小为3,从没有元素开始
从制作人那里得到一些东西,大小还不是3,添加它,不要阻塞
从制作人那里得到其他东西,大小还不是3,添加它,不要阻止
从制作人那里得到其他东西,大小还不是3,添加它,不要阻止
从制作人那里得到其他东西,尺寸现在是3,直到有东西被拿走为止
从制作人那里得到其他东西,尺寸仍然是3,直到有东西被拿走为止
一个使用者从队列中取出,通知(5)和(6)中的线程,第一个被调度的线程获得足够长的锁以添加他的元素,另一个被强制再次阻塞,直到另一个使用者从队列中取出
以下是您的实际操作,如书面所示:
队列的最大大小为3,从没有元素开始
从制作人处获取内容,大小尚未达到3,在wait()
上阻止,但不添加内容
从制作人处获取内容,大小尚未达到3,在wait()
上阻止,但不添加内容
从制作人处获取内容,大小尚未达到3,在wait()
上阻止,但不添加内容
在添加元素的所有3种情况下,元素实际上并没有被添加,我们被困在wait()
,因为所有3种情况都在循环时进入,然后没有任何东西调用notifyAll()
您在评论中的修复:
while (q.size() == size)
这使它可以执行它应该执行的操作:如果大小已经达到最大值,则阻塞,直到通过通知通知它继续,然后检查大小是否仍然是最大值。对于上面示例中在收到通知后接收锁的线程(例如步骤6中的线程),它将有机会添加其消息。未接收锁的线程将在第一个线程释放锁后接收锁,但大小将再次增加到最大大小,从而导致它再次阻塞。尽管如此,我认为你的方法是一个良好的开端
代码中有一点是不正确的,那就是在添加后调用了notifyAll
。添加不会导致队列大小缩小,但您会通知在putTail
方法中等待的所有线程继续。如果您只是在队列中添加了使其达到最大大小的内容,那么没有理由通知正在等待向队列添加内容的线程。我想你的意思是让notify对等待你最终的take
方法的线程做些什么,这就引出了我的下一点:
下一步是使用两个锁定对象,而不是总是使用this
。这样,take
方法可以与put
方法分开进行阻塞。在put
方法中使用一个锁来wait
,在take
中使用notifyAll
,然后在take
方法中使用另一个锁来wait
,在put
中使用notifyAll
。这将使您可以单独通知接球手和推杆手,而无需像使用此选项那样立即通知所有接球手和推杆手。notifyAll
我解决消费者-生产者问题的方向正确吗?我能改变什么?@思考者:TBH,我不认为你是。以下可能是一个好的开始:我可以在putTail方法中更改什么?这真的正确吗wait()
在上释放监视器,并允许其他对象在其上同步,因此我认为实际发生的情况是所有三个线程最终都在等待wait()
调用。我尝试了调试。我猜所有3个线程都卡在wait()上。我应该怎么做?您是否出于学习原因实施了自己的队列
?您可以使用JDK.Yes中已有的BlockingQueue
实现之一。只是为了学习。我尝试过使用BlockingQueue。我想测试“等待”和“通知”。这就是为什么我创建了自己的队列BlockingQueue
会为你做这件事,因为get
方法会一直阻止,直到队列中有东西出现为止。我知道这就是为什么我创建了自己的队列。哦-你及时删除了灾难性的“静态”建议-即将否决投票!
0
1
2
while (q.size() == size)