关于线程可见性的理解

保证线程可见性最简单的方法是使用volatile修饰变量,对象(不保证被修饰对象的内部对象的可见性),或者CAS自旋,synchronized来完成

CAS自旋参考java.util.concurrent.atomic下的 AtomicBoolean 等实现compareAndSwap,但是是个硬件级别的本地方法.

废话不多说,上代码,看注释

package thread.base.visibility;

import java.util.concurrent.TimeUnit;

/**
 * 
 * @author ZhenWeiLai
 *
 */
public class TestVisibility {
    String str = null;//将会被另一个线程修改
    String temporary = null;//保存str被修改前的值
    String template = "ABC";//String模板,循环连接直到超出CPU缓存

    //构造时连接字符串
    public TestVisibility() {
        StringBuilder sb = new StringBuilder();
        /**
         * 在我的CPU(4790K)上,这里设置为 100000 就能达到终止循环的效果,取决于CPU的缓存大小
         * 把循环次数减少,能达到被CPU缓存,到达死循环的效果
         */
        for (int i = 0; i < 100000; i++) {
            sb.append(template);
        }
        temporary = sb.toString();
        str = sb.toString();
    }

    public void increment() {
        /**
         * 判断str的值是否等于temporary的值,如果str存在cpu缓存,那么将会是死循环
         * 如果不存在cpu缓存,那么将会去主内存查找,循环将结束
         */
        while (str.equals(temporary)) {
            //注意这里不能System.out 因为这样会强制刷新cpu缓存中str的值,原因不明
       //有的说法是jvm在一个变量读写频率很高的情况下,才不会把数据及时写进内存,但是如果在这里调用System.out.println的话,那么读取str的频率将会变低,所以就写入了内存
/** * Thread.yield() 可以让步CPU,有可能从主内存中刷新数据 * 我的理解是,把CPU让出来让其他线程执行,那么缓存很可能被其他数据给使用了 * 导致不得不去主内存中重新读取 */ // Thread.yield(); } } public static void main(String[] args) { TestVisibility tv = new TestVisibility(); //一个线程开启执行循环方法 new Thread(() -> { try { tv.increment(); } catch (Exception e) { e.printStackTrace(); } }).start(); try { //主线程等待两秒,让循环飞一会 TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } /** * 另一个线程修改str的值 */ new Thread(() -> { tv.str = "aa"; }).start(); } }

 

转载于:https://www.cnblogs.com/sweetchildomine/p/6564627.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值