01 April 2018

图上纠正:staticInt 会在不同线程同步,时机不确定,但是忙碌时候另外一个线程只能用本线程 staticInt 的copy
Stream Arch

static 静态部分 在类加载的时候会在类对象保留一份,此类的实例间共享一份静态资源,并加载到内存,寄存器,缓存,不保证每个线程看到的值是一致,最新值(假设有线程对静态变量修改的话);而volatile表示每次保证读取到到是主内存中最新的值。
现在JVM经过优化,已不会出现liveness failure 。所以没事别用volatile。1.7前知名bug

原始代码 优化代码
while(!flag){} if(flag){
&nbps;&nbps;&nbps;&nbps;while(true){}
}

死循环, 无volatile 关键字

public class TestWithoutVolatile {
    private static boolean bChanged;

    public static void main(String[] args) throws InterruptedException {
        new Thread() {
            @Override
            public void run() {
                for (;;) {
					if (bChanged == !bChanged) {
                        System.out.println("!=");
                        System.exit(0);
                    }
                }
            }
        }.start();
        Thread.sleep(300);
        new Thread() {
            @Override
            public void run() {
                for (;;) {
                    bChanged = !bChanged;
                }
            }
        }.start();
    }
}

有volatile,正确感知

public class TestWithVolatile {
    private static volatile boolean bChanged;
    public static void main(String[] args) throws InterruptedException {
        new Thread() {
            @Override
            public void run() {
                for (;;) {
                    if (bChanged == !bChanged) {
                        System.out.println("!=");
                        System.exit(0);
                    }
                }
            }
        }.start();
        Thread.sleep(100);
        new Thread() {
            @Override
            public void run() {
                for (;;) {
                    bChanged = !bChanged;
                }
            }
        }.start();
    }
}

测试代码

public class NoVisiblility {
    private static boolean ready;
    private static volatile boolean ready;// if $ready is volatile, this can be avoid as well even without $LINE 1
    private static int number;
    private static int cc;


    private static class ReaderThread extends Thread {
        public void run() { // 读线程
            while (!ready) {
                // $LINE 1
                System.out.println(222);// if this is removed, the copy of $ready will be used for ever
            }
            System.out.println(number);
            System.exit(0);
        }

    }

    private static class ReaderThread extends Thread {
        public void run() { // 读线程
            System.out.println("in");
            for (;;) {//  等价 while(!ready)
                // boolean aa = ready; 即使加入本变量 $aa 的读,也还是读取本地static copy
               // cc = 1; 即使加入其他变量的读写,也还是读取本地static copy
                // 如果执行ready = false; 就会同步$ready 在主存中的值,系统执行$LINE 2
                 if (ready) {
                    break; // $LINE 2
                }
            }
            System.out.println(number);
            System.out.println("exit");
            System.exit(0);
        }

    }


    public static void main(String[] args) throws InterruptedException { // 主线程
        new ReaderThread().start();
        Thread.sleep(10);
        new Thread(new Runnable() {

            @Override
            public void run() {
                for (;;) {
                    ready = true;
                    number = 42;
                }
            }
        }).start();;
    }
}


blog comments powered by Disqus
Flag Counter