难道是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里是否依然遵循这个规范。 |