制片人和消费者线程挂起

时间:2012-04-11 07:40:55

标签: java multithreading command-line

所以这是我第一次涉足线程,到目前为止它让我疯狂。我的问题似乎是某种同步错误导致我的消费者线程挂起。我已经查看了其他代码以及我能找到的所有内容,但我无法找到我的错误。在Eclipse中执行的代码与命令行中的javac之间似乎也存在差异。

意图 - 使用有界缓冲区(1000个插槽)创建并消耗1,000,000个双打。仅使用通知并等待。

问题 - 在Eclipse中,消费者线程偶尔会挂起940,000次迭代,但其他时间完成。在命令行中,使用者线程始终挂起。

4 个答案:

答案 0 :(得分:2)

Wait()方法可能以虚假方式中断(即没有通知),请参考here。因此,您需要将所有if (condition) { wait(); }替换为while (condition) { wait(); }。也许这就是原因。

答案 1 :(得分:1)

你与addPlacegetPlace搞混了。为清楚起见,我将其重命名为nextWritenextRead。所以这是你的add()

if ((nextWrite + 1) == nextRead) {
  wait();
}
buff[nextWrite] = someRandomNumber;
nextWrite = (nextWrite + 1) % 1000;
notify();

这是你的get()

if (nextRead == nextWrite) {
  wait();
}

逻辑错误是显而易见的:因为nextWrite在[0; 999],nextWrite + 1将在[1; 1000],但nextRead只能在[0; 999]。每次nextWrite999nextRead0时,wait来电将永远不会执行,而制作人可能覆盖尚未读取的数据。

生产者可能会在某些时候停止覆盖,但是在一个假想的多核计算机上有效,其中一个核心比另一个核心快一百万倍,生产者将完成其run()并将终止,因为它只会停止何时nextWrite + 1 == nextRead

在我们想象的机器上,只要nextRead变为0,消费者就会挂起(因此等于生成器最后设置为nextWrite的{​​{1}},因为它运行正好一百万次迭代,你的缓冲计数器被定义为0),因为在那一刻,生产者通知i % 1000,但由于它已经终止,所以不会有任何通知到达。

This is an improved(并且正常工作)您的代码版本

修改 我忘记了(琐碎的)解决方案:

wait()

答案 2 :(得分:0)

好吧,我认为我的程序中存在逻辑问题。 在标准的Produce-Consume例程中,您可以根据需要生成,但只有在生成的内容时才可以使用。

在你的实现中,你生产,等到它消耗,然后再生产。

我认为这不是你打算做的。

从add方法中删除wait()块,并从get()方法中删除notify()。 另外,我认为在main中不需要使用线程join()。

编辑:你的get()方法总是进入wait()。即使制片人已经完成了它的工作。想一想。如果Producer已经完成了它的工作,你就不会得到notify()。

答案 3 :(得分:0)

有些观点:

  • 在Java中,通常第一个类名称char必须为大写:所以请调用您的类ProducerConsumerBuffer
  • 当你说你在Eclipse / Command Line上尝试这个时,它意味着你在Eclipse和Consumer中运行生产者命令行,反之亦然?如果是这样,它就无法运行,buffer不会在两个进程之间共享。