volatile jls的例子

时间:2013-01-13 19:29:07

标签: java multithreading concurrency volatile jls

以下代码是否应该按照JLS example for volatile在Windows 7 x86 jdk 7(打开-ea)上抛出AssertionError?

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 个答案:

答案 0 :(得分:4)

您有多个线程正在运行oneij是易变的,因此更改将是可见的,但i++j++不是原子操作,并且其中一个计数器很可能不会在某个阶段适当增加:

假设我是5,例如,显示一个可以抛出AssertionError的有效线程交错:

  • 线程1:读取i =&gt; 5
  • 线程2:读取i =&gt; 5
  • 线程1:temp = i + 1 =&gt; 6
  • 线程2:temp = i + 1 =&gt; 6
  • 线程1:写i = temp =&gt; 6
  • 线程2:写i = temp =&gt; 6
  • 线程1:读取j和增量=&gt; j = 6
  • 线程2:读取j和increment =&gt; j = 7

i和j不同步,one中的断言将失败。

但是,尽管存在数据竞争,但程序运行仍然可能不会引发断言错误:JLS不能保证您的程序运行良好,但它并没有说它赢了“要么。

编辑:其中一位编写JLS“线程和锁定”部分的人实际上有一个post on his blog关于一个非常相似的问题。这些评论甚至提到了你在问题中提到的JLS部分:JLS示例中只有一个写作线程。