Java共享变量可见性研究(一)

1.在主线程启动另一个线程thread1

public static void main(String[] args) {
        Runnable demo = new MyRunnable(bonkBean);
        Thread thread = new Thread(demo,"thread1");
        /*try {
            Thread.sleep(1000);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        flag = true;
        thread1.start();
   
        /*try {
            Thread.sleep(5000);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }*/
    }
    
    private static class MyRunnable implements Runnable {  
        @Override
        public void run() {
            //System.out.println(Thread.currentThread().getName() + ":" + flag);
            //synchronized (AbstractThriftCodecManagerTest.class){}
            while (true) {
                //synchronized (AbstractThriftCodecManagerTest.class){}
                if (flag) {
                    break;
                }
            }
            System.out.println("执行完毕");
            // System.out.println(Thread.currentThread().getName()+":"+ a);
        }
    }

  按照正常情况,flag作为基础类型变量被主线程和线程1在工作内存中保存一份副本,故主线程修改flag为true之后不能保证一定会写回到主存中去,因此在大多数情况下线程1会一直执行下去。但是主线程将flag设置为true后再启动线程1后,线程1会立即执行结束。原因如下:
  Java内存模型遵循着一个Happens-Before规则,其中有一个线程启动原则,即:
  调用start方法时,会将start方法之前所有操作的结果同步到主内存中,新线程创建好后,需要从主内存获取数据。这样在start方法调用之前的所有操作结果对于新创建的线程都是可见的。
因此线程1启动后,读取到的flag变量是true。
在没有研究这个happens-before原则之前,有考虑过从主线程启动的线程1是不是将主线程的flag副本的值给复制过去了,即所谓子线程继承父线程的部分资源,虽然最后发现和父子线程继承没有关系,但也知道了通过InheritableThreadLocal这个继承自ThreadLocal的类是可以达到子线程初始化时复制父线程的InheritableThreadLocal类型变量的目的的,从而实现继承。
拓展链接:
1、https://www.cnblogs.com/cookiezhi/p/5774583.html

你可能感兴趣的:(Java多线程)