多线程几个有趣案例分析

主线程开子线程

	boolean flag=true;
    public static void main(String[] args) throws InterruptedException {
        TestThread t = new TestThread();
        t.start();//开子线程 1
        t.flag = false;//主线程继续跑 2
        //绝大部分情况下都是2先执行,所以下面的输出语句不会执行
    }
    private void start() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(flag){
               		 System.out.println("sub thread");
                }
            }
        }).start();
    }

JIT激进优化产生的可见性问题

	boolean flag=true;
    public static void main(String[] args) throws InterruptedException {
        TestThread t = new TestThread();
        t.start();//开子线程 1
        Thread.sleep(1000);
        t.flag = false;//主线程继续跑 2
        //绝大部分情况下都是2先执行,所以下面的输出语句不会执行
    }
    private void start() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(flag){
               		 System.out.println("sub thread");
                }
            }
        }).start();
    }

在休眠1s后再把flag置为false;结果是程序打印了1s的sub Thread,这一点符合我们的正常逻辑。
重点来了,如果我们把 System.out.println(“sub thread”);这条语句删除,那么这段程序永远不会停止。
这就令人很费解

见下面的程序

	boolean flag=true;
    public static void main(String[] args) throws InterruptedException {
        TestThread t = new TestThread();
        t.start();//开子线程 1
        Thread.sleep(1000);
        t.flag = false;//主线程继续跑 2
        //绝大部分情况下都是2先执行,所以下面的输出语句不会执行
    }
    private void start() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(flag){
               		 //空轮询,永远不会停止
                }
            }
        }).start();
    }

问题分析:既然一直空轮询,那么可以确定的是子线程的flag一直是true,即使主线程已经修改为false。
什么原因导致flag一直是true,我先列举了一系列可能的原因如下:
原因一:主线程的flag对子线程不可见,加volatile关键字解决。
这个原因可以排除掉,就算我们的flag不是volatile的,但是总有一个时刻子线程会发现flag被改为flase了吧,不可能一直发现不了啊!并且加了打印语句1s过后程序停止,说明绝不是这个原因。
原因二:JVM晚期优化?
对于上面的空轮询,他认为是可以优化的,类似优化成下面的样子:
把flag暂存起来,这样就不用每次都去堆里面找。这样temp就一直都是true。

	private void start() {
        new Thread(new Runnable() {
        boolean temp = flag;
            @Override
            public void run() {
                while(temp){
               		 //空轮询,永远不会停止
                }
            }
        }).start();
    }

而对于再while里面加了打印语句(打印也是方法调用)或者一些方法调用JIT不敢做优化。
上面这些我不敢保证绝对正确,毕竟我不知道怎么可以验证JIT确实对我的空轮询做了晚期优化,这些都只是猜测。
深入理解java虚拟机11章节 深入讲了JIT晚期优化,看的很晕,毕竟基本纯理论,很难验证。