java 线程问题?
public class ThreadTest {
public static void main(String[] args){
System.out.println("11111");
SubThread st=new SubThread();
st.start();
while(st.getFlag()){
}
System.out.println("22222");
}
}
public class SubThread extends Thread{
private boolean flag=true;
public boolean getFlag(){
return flag;
}
public void run(){
try {
sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
flag=false;
}
}
这样的话 22222永远输不出来, 但在 getFlag()上加上 synchronized就可以了。
还有一种就是不加 synchronized 但在while() 循环中加上一点输出(简单的操作),又可以输出了, 谁能详细解释下吗?
计算机科学等 7 个话题下的优秀答主
15 人赞同了该回答
从另一个问题传送过来 如何查看Java代码的汇编形式? - 计算机
题主的问题在这帖里有详细解释:有没有什么工具可以查看正在运行的类的c/汇编代码
Android 开发话题下的优秀答主
看看你的JVM把这一段编译出的虚拟机指令是什么就知道了
发现更大的世界
9 人赞同了该回答
被优化掉了,getFlag只读一次到寄存器,然后就不会再读了。
另外,signal最好别这么写……一般都会有专门的spinLock或者semaphore可以用。
(学好编译原理和操作系统就不会问这个问题了,所以你们看,所谓三大浪漫不是没用的……)
需要把flag变量声明为volatile,保证flag变量永远位于内存中,否则jvm可能会缓存flag到寄存器
出现这种问题可能是主线程在使用subThread实例的时候将subTread实例包括flag变量的值copy了一份到主线程的栈中缓存起来,之后Main线程中访问subThread的时候会从缓存中读取flag的值。而subThread中改变flag的值并没有改变Main线程中缓存的值,因此导致死循环。
当然同样的代码我在我电脑上运行是不会产生死循环,可能跟jvm版本和启动参数有关。
可以尝试给flag变量添加volatile关键字让每次访问该变量时都从主存中同步一下该变量的最新值。看看能不能解决问题。
也可能Main线程while(true)中没有io操作,导致volatile线程一直没有被调度,所以flag一直没有被设置
赞同 41 条评论
分享
收藏喜欢
继续浏览内容
心有所想,但有所为。个人公众号:think123
5 人赞同了该回答
你这里相当于有两个线程了,多次执行结果肯定不一致,你出现这样的情况很明显是主线程抢到了优先权,先执行,所以得到的
Flag就为true了,就一直执行死循环了,当子线程抢到执行权的时候改变了状态又没有通知主线程,所以会出现这种情况,当然你也可以理解这个变量放到了主线程的栈中,没有及时更新,所以你要做的就是通知它就可以了
赞同 5添加评论
分享
收藏喜欢
life is short
1 人赞同了该回答
while那句被优化成
if(st.getFlag)
while(true)
建议你看一下 effective java,里面有一节专门讲这个
典型的JMM可见性问题,使用final或者vilotile或者synchronize都可以解决问题。
但是不好测试,即使你每次运行的结果都是正确的也不代表代码是正确的。这个可以参考R大大的回复看运行时的汇编。
volatile 保证可见性,了解一下