所以这是我第一次涉足线程,到目前为止它让我疯狂。我的问题似乎是某种同步错误导致我的消费者线程挂起。我已经查看了其他代码以及我能找到的所有内容,但我无法找到我的错误。在Eclipse中执行的代码与命令行中的javac之间似乎也存在差异。
意图 - 使用有界缓冲区(1000个插槽)创建并消耗1,000,000个双打。仅使用通知并等待。
问题 - 在Eclipse中,消费者线程偶尔会挂起940,000次迭代,但其他时间完成。在命令行中,使用者线程始终挂起。
答案 0 :(得分:2)
Wait()
方法可能以虚假方式中断(即没有通知),请参考here。因此,您需要将所有if (condition) { wait(); }
替换为while (condition) { wait(); }
。也许这就是原因。
答案 1 :(得分:1)
你与addPlace
和getPlace
搞混了。为清楚起见,我将其重命名为nextWrite
和nextRead
。所以这是你的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]。每次nextWrite
为999
或nextRead
为0
时,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)
有些观点:
Producer
,Consumer
和Buffer
。buffer
不会在两个进程之间共享。