关于JAVA线程的一个奇怪的现象

       在学习JAVA线程时候的遇到一个很奇怪的现象。让我们先来看代码

public class TestThread {

    public static void main(String[] args) {
        IRun ir = new IRun();
        Thread it = new Thread(ir);
        it.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            Logger.getLogger(TestThread.class.getName()).log(Level.SEVERE, null, ex);
        }
        ir.setStop();
    }

    static class IRun implements Runnable {
        boolean exec = true;
        public void setStop() {
            exec = false;
            System.out.println("exec = " + exec);
        }
        @Override
        public void run() {
            int c = 0;
            while (exec) {
                c++;
            }
            System.out.println("退出了循环");
        }
    }
}
         在上述程序首先创建一个Runnable对象ir,然后创建一个线程对象it,通过it.start()启动线程,执行IRun类中的run()函数,执行一个while循环。while循环的条件由布尔变量exec控制。主程序中等待1秒钟后,修改exec的值为false,按照正常的逻辑应该是在exec值为false后,循环结束执行下面输出语句,然后线程结束,程序退出。

        但是,上述代码在运行后,将不会执行run()函数中的System.out.println("退出了循环");语句,程序一直保持运行。对这种现象,在帖子”关于JAVA线程,请大神帮忙“中still_rain给出的这种现象的原因是线程访问的同步问题导致,当主线程(main函数所在的线程)中修改变量exec的值后,在创建执行的线程中访问的exec的值没有发生变化(或者说可能是主线程、执行线程这两个线程exec变量是不同的对象,好像是说java会将一些资源在每个线程中复制一份?有待确认)。在exec变量前加上volatile修饰符后,程序运行正常,问题似乎解决。

       现在以上述代码为基础,进行一次小小的修改。在run()函数中的while循环中加上一个类对象操作,比如新建一个字符串,则run()函数为

 public void run() {
            int c = 0;
            while (exec) {
                String s = new String("");
                c++;
            }
            System.out.println("退出了循环");
        }
    }
       运行程序,程序按预期的顺序执行,顺利结束。这时候不管exec变量是否有volatile修饰符,且只在while循环中存在类对象操作(新建对象、对象函数调用(调用的函数不能返回基本数据类型),以及像System.out.println这样的操作),程序的运行都很正常,对这种现象就不是上述的同步问题能够解释的了。在帖子” 关于JAVA线程,请大神帮忙“中 still_rain(感谢热情的回复)从编译器优化的角度进行了解释。当while循环中只有简单的基本数据类型参与运算的时候由于执行速度太快,将while循环编译成了while(true)语句。导致循环不会退出,从而循环后的输出不会执行,且程序不会退出。

       为了探究这个奇怪现象的原因,让我们看看编译后的字节码,下图是用jclasslib查看的字节码,是修改前的run()函数字节码。




从图中可以看到,循环体从aload_0开始,到goto 2结束。控制跳转的语句是ifeq 15,意思是如果值为0则跳转到15,否则执行下面的语句。

当将上面的while(exec)语句修改为while(true)后,字节码为:




由两图可以看出,编译器并没有将while(exec)语句优化为while(true)。再看修改后的代码编译的字节码:




循环体从aload_0起,到goto 2结束。从ifeq 25下面的一行到astotre_2行,为String s = new String("");语句的字节码,将这段去掉则字节码与修改前的一样。所以基本可以排除编译器优化导致的程序不正常运行。

请看到这篇文章的大神们能够给予指导,探究出现这种情况的原因,谢谢


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fengdavid

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值