学习编译原理对下面这段java跳不出死循环大概能有较好的解释吧

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一直没有被设置

发布于 2015-01-11

​赞同 4​​1 条评论

​分享

​收藏​喜欢

继续浏览内容

 

 

心有所想,但有所为。个人公众号:think123

5 人赞同了该回答

你这里相当于有两个线程了,多次执行结果肯定不一致,你出现这样的情况很明显是主线程抢到了优先权,先执行,所以得到的
Flag就为true了,就一直执行死循环了,当子线程抢到执行权的时候改变了状态又没有通知主线程,所以会出现这种情况,当然你也可以理解这个变量放到了主线程的栈中,没有及时更新,所以你要做的就是通知它就可以了

发布于 2015-01-12

​赞同 5​​添加评论

​分享

​收藏​喜欢

 

heshan

life is short

1 人赞同了该回答

while那句被优化成
if(st.getFlag)

while(true)

建议你看一下 effective java,里面有一节专门讲这个

 

 

典型的JMM可见性问题,使用final或者vilotile或者synchronize都可以解决问题。

但是不好测试,即使你每次运行的结果都是正确的也不代表代码是正确的。这个可以参考R大大的回复看运行时的汇编。

发布于 2015-01-18

 

volatile 保证可见性,了解一下

https://www.zhihu.com/question/27500017

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值