Java 生产者和消费者线程挂起
这是我第一次尝试线程,到目前为止,它让我发疯。我的问题似乎是某种同步错误导致消费者线程挂起。我看过其他代码,几乎所有我能找到的东西,但我找不到我的错误是什么。在Eclipse中执行的代码和通过命令行中的javac执行的代码之间似乎也存在差异 意图-使用有界缓冲区(有1000个插槽)创建并消耗1000000个双倍。仅使用通知和等待Java 生产者和消费者线程挂起,java,multithreading,command-line,Java,Multithreading,Command Line,这是我第一次尝试线程,到目前为止,它让我发疯。我的问题似乎是某种同步错误导致消费者线程挂起。我看过其他代码,几乎所有我能找到的东西,但我找不到我的错误是什么。在Eclipse中执行的代码和通过命令行中的javac执行的代码之间似乎也存在差异 意图-使用有界缓冲区(有1000个插槽)创建并消耗1000000个双倍。仅使用通知和等待 问题-在Eclipse中,使用者线程偶尔会挂起大约940000次迭代,但其他时间会完成。在命令行中,使用者线程总是挂起。嗯,我想我看到了程序中的逻辑问题。 在stand
问题-在Eclipse中,使用者线程偶尔会挂起大约940000次迭代,但其他时间会完成。在命令行中,使用者线程总是挂起。嗯,我想我看到了程序中的逻辑问题。 在standart生产-消费程序中,您可以生产任意数量的产品,但您只能在有产品生产的情况下进行消费 在您的实现中,您生产,等待它被消耗,然后再次生产 我想这不是你想做的 从add方法中删除wait()块,从get()方法中删除notify()。 另外,我不认为线程join()在main中是必要的 编辑:并且get()方法总是进入wait()。即使制片人已经完成了工作。想想看。如果制作人已经完成了它的工作,您将不会得到notify()
Wait()
方法可能以虚假方式中断(即,不通知),请参阅。因此,您需要将所有的if(条件){wait();}
替换为while(条件){wait();}
。也许这就是原因。有几点:
- 在Java中,通常第一个类名char必须是大写的:因此调用类
、Producer
和Consumer
Buffer
- 当您说您在Eclipse/命令行上尝试此操作时,这意味着您在Eclipse中运行producer,在命令行中运行Consumer,反之亦然?如果无法工作,则两个进程之间不共享
缓冲区
addPlace
和getPlace
。为了清楚起见,我将它们重命名为nextWrite
和nextRead
。这就是你的add()
这是你的get()
逻辑错误显而易见:由于nextWrite
在[0;999]范围内,nextWrite+1
将在[1;1000]范围内,但nextWrite
只能在[0;999]范围内。每次nextWrite
为999
或nextrade
为0
,将永远不会执行wait
调用,并且生产者可能会覆盖尚未读取的数据
生产者可能会在某个点停止覆盖,但实际上,在一个虚拟的多核机器上,一个核的速度比另一个快一百万倍,生产者将完成其run()
并终止,因为它只在nextWrite+1==nextRead
时停止
在我们想象的机器上,消费者将在nextRead
变为0
时挂起(因此等于nextWrite
,生产者最后将其设置为0
,因为它运行了100万次迭代,而缓冲区计数器被定义为i%1000
),因为此时它将等待()
,但由于制作人的通知已终止,因此不会收到任何通知
(和工作)代码的版本
编辑
我只是忘记了(琐碎的)解决方案:
public synchronized void add(double randomNumber) throws InterruptedException {
if((nextWrite + 1) % 1000 == nextRead)
wait();
buff[nextWrite] = randomNumber;
nextWrite = (nextWrite+1)%1000;
notify();
}
最好停止使用“支持”虚假唤醒的操作系统:)哪个操作系统支持?我不知道这一点,所以很有趣:)好吧,只有U**x类操作系统支持这一功能。这是企鹅特有的,我看你已经试过了“//if(I>999000)”。这是否表示使用者线程尚未完成,因为一个或多个队列对象已“丢失”,或者使用者因其他原因卡住?您可能希望尝试将整数排队,并在使用者中检查接收到的每个值(第一个除外)是否比最后一个值多一个,如果不是,则立即停止/例外。随机双倍几乎是你可以选择排队的最糟糕的事情,因为在消费者中很难检查/比较它们。+1对我来说很好。我很惊讶,我没有注意到在检查缓冲区是否已满时未能包装索引。遗憾的是,OP并没有简单地将递增的整数后置,并在消费者中检查它们——一个问题的关闭是显而易见的。当然,打印整数他很快就会发现这一点。也许他不会在这里发布:P我也没有注意到,直到我用有意义的名字重构了他的代码,逻辑错误立即出现。非常感谢你的帮助,但是我认为这已经扭转了问题。它现在在生产者线程中的999999处间歇性挂起。使用者线程终止,如果生产者位于9999999,则不可能终止。@user972425
add
和get
中的if
前置码应为while(){wait();}
if (nextRead == nextWrite) {
wait();
}
public synchronized void add(double randomNumber) throws InterruptedException {
if((nextWrite + 1) % 1000 == nextRead)
wait();
buff[nextWrite] = randomNumber;
nextWrite = (nextWrite+1)%1000;
notify();
}