昨天写程序遇到一个坑,花了很久才找到是为什么。以往程序出错主要还是自身原因,这算是第一个类似bug的存在。这做下记录。
本来是希望写一个检测标志位的程序,因为耗时很短,我就简单的写了个while循环去检测。结果程序在调试状态下很好的运行,但是直接运行就不行。
后来发现while循环似乎做了一些优化。如果while后面不加任何语句而直接以分号结尾,则程序检测一段时间后就不在继续检测了(类似挂起,但具体是不是挂起还有待研究)。如果是在多线程情况下while的判断语句必须加volatile否则程序会卡在while循环这里。
这里写个简单的demo来说明一下这个问题:
public class Test {
public static void main(String[] args) throws InterruptedException {
A a = new A();
a.start();
System.out.println(a.flag);
// Thread.sleep(10); //不加延时会正常运行
System.out.println(a.flag);
a.flag=true;
}
}
class A extends Thread{
boolean flag;//加上volatile则4种情况都可以正常运行
public A(){
flag = false;
}
public boolean isFlag() {
return flag;
}
@Override
public void run(){
// while(!isFlag());//无法正常运行
// while(!flag);//无法正常运行
// while(!isFlag())System.out.println("pass");;//正常运行
// while(!flag)System.out.println("pass");//正常运行
System.out.println("finish");
}
}
这里讨论了四种情况,首先这种异常的情况只有在一个线程使用while检测标志位并且,直接以分好结尾,而使用第二个线程改变while循环的判断条件的时候才出现,而且第二个线程如果在一定时限内改变则可以正常运行,只有在第一个线程进行while判断一段时间后(这里是10ms)之后再进行改变,则第一个线程会卡在while循环处不能正常运行。
出现的情况和while循环的判断语句无关。
解决的方案目前发现两种,一种是while不直接加分号,而是进行一些操作,则不会出现异常情况。另一种是使用volatile标志位。
目前还不清楚出现这样情况的原因。不过这样的情况最好还是用waitnotify的方法来做比较好
运行环境:
操作系统:Ubuntu 14.04
IDE:myeclipse 2014.
JRE:java1.7
update 2016.11.23
现在想来应该是内存可见性问题。并不是什么bug。。我二逼了。。