这个Java程序可以打印除零以外的值吗?

这个Java程序可以打印除零以外的值吗?,java,multithreading,Java,Multithreading,我有一个最喜欢的C#程序,类似于下面的一个程序,它显示如果两个线程共享相同的内存地址进行计数(一个线程递增n倍,一个线程递减n倍),则可以得到除零之外的最终结果。只要n相当大,就很容易让C#在[-n,n]之间显示一些非零值。然而,即使将线程数增加到1000(增加500个,减少500个),我也无法让Java产生非零结果。是否存在一些内存模型或规格差异wrt C#我不知道,尽管我不知道调度或内核数量,但该程序始终会产生0?我们会同意这个程序可以产生一个非零值,即使我们不能通过实验证明这一点吗 (不是

我有一个最喜欢的C#程序,类似于下面的一个程序,它显示如果两个线程共享相同的内存地址进行计数(一个线程递增n倍,一个线程递减n倍),则可以得到除零之外的最终结果。只要n相当大,就很容易让C#在[-n,n]之间显示一些非零值。然而,即使将线程数增加到1000(增加500个,减少500个),我也无法让Java产生非零结果。是否存在一些内存模型或规格差异wrt C#我不知道,尽管我不知道调度或内核数量,但该程序始终会产生0?我们会同意这个程序可以产生一个非零值,即使我们不能通过实验证明这一点吗

(不是:,我发现这个问题完全解决了,但当我运行该主题的代码时,我也得到了零。)

公共类计数器
{
专用int_计数器=0;
计数器()引发异常
{
最终整数限制=整数最大值;
线程添加=新线程()
{
公开募捐
{

对于(int i=0;i您给出的代码只在一个线程上运行,因此将始终给出一个0的结果。如果您实际启动两个线程,您确实可以得到一个非零的结果:

// Don't call run(), which is a synchronous call, which doesn't start any threads
// Call start(), which starts a new thread and calls run() *in that thread*.
add.start();
sub.start();

在我的测试运行框中,给出了-2146200243。

您给出的代码只在一个线程上运行,因此将始终给出一个0的结果。如果您实际启动两个线程,您确实可以得到一个非零的结果:

// Don't call run(), which is a synchronous call, which doesn't start any threads
// Call start(), which starts a new thread and calls run() *in that thread*.
add.start();
sub.start();

在我的测试框中,它给出了-2146200243。

你的程序的问题是你没有创建一个操作系统线程,所以你的程序本质上是单线程的。在Java中,你必须调用
thread.start()
来创建一个新的操作系统线程,而不是
thread.run()
。这与最初的Java API中犯了一个令人遗憾的错误有关。这个错误是设计人员使
线程
实现
可运行

add.start();
sub.start();
add.join();
sub.join();

程序的问题在于您没有创建操作系统线程,因此程序基本上是单线程的。在Java中,必须调用
thread.start()
来创建新的操作系统线程,而不是
thread.run()
。这与最初的Java API中犯了一个令人遗憾的错误有关。这个错误是设计人员使
线程
实现
可运行

add.start();
sub.start();
add.join();
sub.join();

假设你的意思是开始,而不是运行

在大多数常见的平台上,它很可能会产生非零,因为在多核的情况下,
+
/
-
不是原子操作。在单核/单CPU上,您很可能会得到0,因为如果编译到一条指令(
添加
/
inc
),则
-
是原子的但这部分取决于JVM


在这里检查结果:

假设您真正的意思是
开始
,而不是
运行

在大多数常见的平台上,它很可能会产生非零,因为在多核的情况下,
+
/
-
不是原子操作。在单核/单CPU上,您很可能会得到0,因为如果编译到一条指令(
添加
/
inc
),则
-
是原子的但这部分取决于JVM


检查这里的结果:

我猜您的意思是调用
start()
而不是
run()
,否则你就没有额外的线程了。有时我真的不明白Java虚拟机内部在运行我的程序时发生了什么。JRE执行了一些优化,在这种情况下,每个线程中都可以缓存分配给整数的值(就像变量“生成”到多个副本)进行最终的“合并”操作,或者谁知道呢…也许线程不是“本机”线程。我们应该看看您平台的JRE代码:)哦,天哪,只是常见的开始-运行混淆?我猜您的意思是调用
start()
而不是
run()
,否则你就没有额外的线程了。有时我真的不明白Java虚拟机内部在运行我的程序时发生了什么。JRE执行了一些优化,在这种情况下,每个线程中都可以缓存分配给整数的值(就像变量“生成”到多个副本)进行最终的“合并”操作,或者谁知道呢…可能线程不是“本机”线程。我们应该看看您平台的JRE代码:)哦,天哪,只是普通的开始-跑步混乱?打我一分钟:\Curse you Jon Skeet!@Jon Ug。我完全是想叫开始的。谢谢你的理智检查。打我一分钟:\Curse you Jon Skeet!@Jon Ug。我完全是想叫开始的。谢谢你的理智检查。