《java并发编程实战》读书笔记一 可见性和重排序现象

第3.1章节《可见性》里给了一段代码:

publci class NoVisibility{
    private static voolean ready;
    private static int number;
    private static class ReaderThread extends Thread{
        public void run() {
            while(!ready)
                Thread.yield();
            System.out.println(number);
        }
    }
    public static void main(String[] args) {
        new ReaderThread().start();
        number = 42;
        ready = true;
    }
}

根据作者意思,NoVisibility可能会输出42,也有可能输出0,甚至可能导致死循环,不会输出。原因是因为没有使用恰当的同步机制,没能保证主线程写入ready和number的值对读线程是可见的。
作者在书中提到两个概念:可见性和“重排序(reordering)”现象。

具体分析:
首先类加载会初始化ready和number的值分别为false和0,我们认为正常情况下,number被赋值为42,ready赋值为true,结果应该为:输出42,读线程、主线程执行完成,结束。
其实不然,还会有另外三种情况:

1.无限循环,number的值为0:在主线程即main方法中对ready的设置(即ready = true)还没来得及写回主存(静态变量保存在方 法区),ReaderThread 线程就已经读取了ready的值(并保留了副本),然后加载到Java栈中,此时ready 一直为false所以出 现死循环。number的值也可以类似推理,在主线程即main方法中对number的设置(即number= 42)还没来得及写回主存(静态变量保存 在方法区),ReaderThread 线程就已经读取了number的值(并保留了副本),然后加载到Java栈中,此时number一直为0(只是没 有打印出来而已);

2.无限循环,number的值为42:在主线程即main方法中对ready的设置(即ready = true)还没来得及写回主存(静态变量保存在 方法区),ReaderThread 线程就已经读取了ready的值(并保留了副本),然后加载到Java栈中,此时ready 一直为false所以 出现死循环。在主线程即main方法中对number的设置(即number= 42)后(即number的值已经写回了主 存),ReaderThread 线程才开始执行此时读取的number为42(只是没有打印出来而已);

3.输出0:在主线程即main方法中对ready的设置(即ready = true)后(即ready的值已经写回了主存),还没来得及写回主存(静 态变量保存在方法区),ReaderThread 线程就已经读取了number的值(并保留了副本),然后加载到Java栈中,此时number为0;

至于为什么会出现ready = true写回主存后,number = 42还没写回主存。这应该是由于Java虚拟机的一种优化技术叫指令重排序,number = 42不一定会在ready = true前面执行,得看Java虚拟机是怎么优化的。

内容来源:http://bbs.csdn.net/topics/390715765/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值