Java 程序不总是终止?

Java 程序不总是终止?,java,multithreading,Java,Multithreading,我想为我的一个项目测试多线程,试图在出现问题时开发一个解决方案 所以我做了一个小测试: 主要的 (您必须修复导入,我还使用自定义类Executor,尽管这只是ExecutorService的包装) 奇怪的行为是,有时它工作正常,有时不正常(终止线程总数为9,尽管我可以清楚地看到它打印了“我做到了!”并且错误正好出现了10次) 有什么解决办法吗?问题可能是赛车状况。 “++”运算符不是原子运算符。 想象一下下面的场景。同时有两个线程。两者都希望增加一个数字并完成。 该数字的初始值为0。 线程0读取

我想为我的一个项目测试多线程,试图在出现问题时开发一个解决方案

所以我做了一个小测试:

主要的 (您必须修复导入,我还使用自定义类
Executor
,尽管这只是
ExecutorService
的包装)

奇怪的行为是,有时它工作正常,有时不正常(终止线程总数为9,尽管我可以清楚地看到它打印了“我做到了!”并且错误正好出现了10次)


有什么解决办法吗?

问题可能是赛车状况。 “++”运算符不是原子运算符。 想象一下下面的场景。同时有两个线程。两者都希望增加一个数字并完成。 该数字的初始值为0。 线程0读取数字,现在知道它是0。 线程1读取数字,现在知道它是0。 线程0(知道它是0)现在将1写入内存。 线程1不知道该数字已更改,并且仍然相信该数字为0,因此他还将1写入内存

你需要一个同步机制,一个锁,一个信号灯或其他东西

有关更多信息,请查看此链接:

对于您的示例,您可以使用该链接中的“synchronized”示例

向主类添加一个如下所示的方法,以增加
addToCounter
,并向
addToErrorCounter
添加一个方法,以消除错误计数器的影响:

synchronized AddToError(int e){
    addToError += e;
}
synchronized IncCounter(){
    addToCounter++;
}

在testclass中的线程中调用这些方法,而不是增加它们的非同步性。

我猜后缀运算符(
main.addToCounter++
)不是原子的。这行代码可能相当于:

int temp = main.addToCounter;
main.addToCounter = temp + 1;
return temp;
如果多个线程同时执行此操作,则两个线程可能会获得相同的
temp
值(因为两个线程在执行第二个线程之前形成上述伪代码的第一行),因此一旦所有线程完成,计数器总数将太小。有关更多信息,请参阅


这种情况下的一个快速修复方法是将
addToCounter
设置为原子整数,然后使用
addToCounter.incrementAndGet()
代替
addToCounter++

@Downvoter,想不想说为什么会有否决票?为什么不让每个线程也说出它的名称,这样你就可以知道哪个线程正在开始/结束,并将线程数减少到5,以帮助减少故障排除的次数?你说它的名称是什么意思?所有线程都使用相同的类,唯一的“移动”部分是
Math.random()
。我不明白在这里说这个名字有什么用。这一点很容易理解,只需通过step调试器即可。Jarrod,这个问题如何与您列出的问题重复?当然,第一个是相关的,但是刚开始使用多线程java的初级程序员不太可能将这一行识别为问题代码,然后考虑搜索原子性。我觉得你给OP的时间太长了,因为他们的技术水平很高。
synchronized AddToError(int e){
    addToError += e;
}
synchronized IncCounter(){
    addToCounter++;
}
int temp = main.addToCounter;
main.addToCounter = temp + 1;
return temp;