难道是JIT reorder导致的?

yuyijq 2015-04-18
最近在做一个关于可见性相关的实验,然后在jdk 1.8两个不同的小版本之间结果却不同,使用不同的VMOptions也不同,无奈汇编功底太弱,没看懂两个版本生成的汇编有啥不同。先贴代码吧:
Test.java
public class Test {
    private static AddThread[] threads = new AddThread[50];;

    public static void main(String[] args) {
        final Count count = new Count();

        for (int i = 0; i < 50; ++i) {
            AddThread thread = new AddThread(count);
            threads[i] = thread;
            thread.start();
        }

        test();
        System.out.println(count.get());
    }

    static void test(){
          while (true) {
            boolean finish = true;
            for (AddThread thread : threads) {
                if (!thread.finish()) {
                    finish = false;
                    break;
                }
            }
            if (finish) {
                break;
            }

        }

    }
}

AddThread.java
public class AddThread extends Thread {
    //这个上面故意没有加volatile
    private boolean finish;

    private final Count count;
    
    public AddThread(Count count){
        this.count = count;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100000; ++i) {
            count.add();
        }
        finish = true;
    }

    public boolean finish(){return finish;}
}


Count.java
public class Count {
    private int count;
    public synchronized void add() {
        count++;
    }

    public int get() {
        return count;
    }
}


现在结果是,用下面这个版本运行,这个程序是可以获得正确结果并最终停止的:
$ java -version
java version "1.8.0_31"
Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)
$ java Test
5000000

但是在下面这个版本,如果不使用任何其他vmoptions情况下程序是无法停止的,死循环了:
$ java -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)

$ java Test
//死循环,main线程RUNNABLE

但是使用上面的版本,如果使用下面的两种方式运行又是可以正常停止的:
$ java -Xcomp Test
5000000

$ java -Xint Test
5000000

看来是1.8.0_45在mixed的方式运行的时候做了些啥reorder导致的?
mixed的方式先采用解释方式执行,然后可以收集运行信息进一步优化,是这个造成的结果么?
有大牛能给分析分析不~~
youlong699 2015-04-20
这个不用reorder就可以挂吧?  循环是死在test里么?

    private boolean finish; 
这个不加volatile,多线程访问的时候,其他线程如果读到的是work memory 里的‘脏’值,就一直是false,循环结束不了。
http://www.infoq.com/cn/articles/java-memory-model-1
不过没有求证,jdk8里是否依然遵循这个规范。
Global site tag (gtag.js) - Google Analytics