2013-01-13 44 views
1

下面的代码应该不会在Windows 7 x86 jdk 7上引发AssertionError(每个JLS example for volatile带有-ea开启)?挥发性jls示例

public class TestVolatile { 
static volatile int i = 0; 
static volatile int j = 0; 

static void one() { 
    i++; 
    j++; 
    assert (i>=j); 
//:"one: i=" + i + " j=" + j; 
} 
static void two() { 
    //System.out.println("i=" + i + " j=" + j); 
    assert (i<=j); 
    /* 
    System.out.print("<i=" + i); 
    for (int k = 0; k < 1000000; k++); 
    System.out.println(", j=" + j+">"); 
    */ 
} 
public static final int NUM_WORKERS = 4; 

public static void main (String [] args) { 
    final Worker [] workers = new Worker[NUM_WORKERS]; 
    final Thread [] workerThreads = new Thread[NUM_WORKERS]; 

    for (int i = 0; i < NUM_WORKERS; i++) { 
     Worker w = new Worker(i); 
     workers[i] = w; 
     workerThreads[i] = new Thread(w,"workerThread_"+i); 
    } 

    for (int i = 0; i < NUM_WORKERS; i++) { 
     workerThreads[i].start(); 
    } 

} 


} 

final class Worker implements Runnable { 
final int id; 
volatile boolean notDone = true; 


public Worker(int tid){ 
    id = tid; 
} 

@Override 
public void run() { 
    //System.out.println("worker start:" + id); 
    try { 
     while (notDone) { 
      if (id < TestVolatile.NUM_WORKERS - 1) { 
       TestVolatile.one(); 
      } else { 
       TestVolatile.two(); 
      } 
     } 
    } catch (Exception e) { 
     // TODO: handle exception 
     e.printStackTrace(); 
    } 
} 
}; 
+1

我几乎马上就会发现一个错误。 – assylias

+0

你认为哪里出错,为什么?澄清 – exexzian

+0

我也得到了错误,没有任何延迟,并可靠地如此。 –

回答

4

您有超过1个线程正在运行oneij是挥发性的,所以变化将是可见的,但是i++j++不是原子操作,这很可能是一个计数器将无法正确在某些阶段递增:

比方说,我是5,例如,要显示的有效螺纹交织,可以抛出一个AssertionError:

  • 线程1:读I => 5
  • 线程2:读I => 5
  • 线程1:温度= I + 1 => 6
  • 线程2:温度= I + 1 => 6
  • 线程1:写I =温度=> 6
  • 线程2:写I =温度=> 6
  • 线程1:读j和增量=> J = 6
  • 线程2:阅读J和增量=> J = 7

i和j是不同步,您在one断言将失败。

尽管存在数据竞争,程序的运行仍然可能不会抛出断言错误:JLS并不保证您的程序可以正常运行,但它并不会说它赢了也不是。

编辑:编写JLS的“线程和锁”部分的人之一实际上有一个关于一个非常类似的问题的post on his blog。这些注释甚至提到了在你的问题中引用的JLS部分:JLS示例中只有一个写入线程。

+0

+1 volatile并不意味着它的所有操作都是原子的,只能读或写,但不能同时使用。我相信给出的例子只适用于这是执行更新的一个线程。 –

+0

即使只有一个线程正在执行更新,我也不确定该示例是否会通过。但我完全同意这是测试代码中的一个原子问题。感谢球员们,这个地方就像是JLS的实时训练。 – porkchop

+0

挥发性证明的另一个例子不能确保原子性:http://brooker.co.za/blog/2012/11/13/increment.html – porkchop