2011-09-27 47 views
1

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

(不:,我发现这个问题询问过here,但是当我运行该主题的代码我也得到零。)

public class Counter 
{ 
    private int _counter = 0; 

    Counter() throws Exception 
    { 
    final int limit = Integer.MAX_VALUE; 

    Thread add = new Thread() 
    { 
     public void run() 
     { 
     for(int i = 0; i<limit; i++) 
     { 
      _counter++; 
     } 
     } 
    }; 

    Thread sub = new Thread() 
    { 
     public void run() 
     { 
     for(int i = 0; i<limit; i++) 
     { 
     _counter--; 
     } 
     } 
    }; 

    add.run(); 
    sub.run(); 
    add.join(); 
    sub.join(); 

    System.out.println(_counter); 
    } 

    public static void main(String[] args) throws Exception 
    { 
    new Counter(); 
    } 
} 
+3

我猜你的意思是调用''开始的(),而不是'的run()',否则,你有没有额外的线程在所有。 – Progman

+0

有时候我真的不明白当我的一个程序运行时Java VM内部发生了什么。 JRE执行多次优化,在这种情况下,可以通过最终的“合并”操作对每个线程中分配给整数的值进行缓存(如变量“产卵”为多个副本),或者是谁知道......也许线程不是“本地”的线程。我们应该看看你的平台的JRE代码:) – gd1

+0

哦,亲爱的,只是共同的开始<>运行混乱? – gd1

回答

4

你给只运行在单个线程的代码,所以总是会给结果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

殴打我一分钟:\诅咒你Jon Skeet! –

+0

@Jon Ug。我完全打算打电话给开始。感谢您的理智检查。 – Dejas

0

你的程序存在的问题是你没有创建一个操作系统线程,所以你的程序本质上是单线程的。在Java中,您必须调用Thread.start()来创建新的操作系统线程,而不是Thread.run()。这与初始Java API中出现的令人遗憾的错误有关。那个错误是设计师制造Thread执行Runnable

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

假设你的真正用意start,不run

在大多数常见平台上,它很可能会产生非零值,因为在多核心情况下,++/--不是原子操作。在单核/单CPU上,如果编译为一条指令(add/inc),但该部分依赖于JVM,则最有可能得到0,因为++/--是原子。

入住这里的结果:http://ideone.com/IzTT2