关于线程访问另外一个线程的变量问题

关于线程访问另外一个线程的变量问题

之前帮别人调错,遇到一个错误,就是一个线程A访问另外一个线程B的成员变量,并且线程A在构造方法中有线程B的引用,但是无论线程A怎么获取线程B的成员变量都是 null,但是在线程B初始化中已经给成员变量赋值了。
后面解决了很久,没解决出来,然后刚好看到了 指令重排序问题 ,下面我们来看一个例子

public class Test {
    int a = 0;
    boolean flag = false;

    public void writer(){
        a = 1;	//1
        flag =true;	//2
    }

    public void reader(){
        if(flag){	//3
            int i =a*a;	//4
        }
    }
}

问:线程B在执行线程4时,能否看到线程A在操作1对共享变量a的写入呢?
不能

原因如下:
编译器和处理器 在不改变程序执行结构的前提下 会对代码进行重排序来优化,以提高程序的运行速度。
下面分析代码原因: 由于操作1和操作2没有数据依赖关系,编译器和处理器可以对这两个操作重排序;同意,操作3和操作4没有数据依赖关系,编译器和处理器也可以对这两个操作进行重排序。程序执行时序图如下:

程序执行时序图
如图所示, 操作1和操作2做了重排序。程序执行时,线程A首先写标记变量flag,随后线程B读取这个变量。由于条件判断为真,线程B将读取变量a 。此时,变量a没有被线程A写入,在这里多线程程序的语义被重排序破坏了!

那如何避免这种情况

加一个 volatile 关键字
因为volatile 关键字
保证了 该变量的可见性 (可见性是啥?要讲的话要花很长篇幅去将,感兴趣的读者去百度找找相关资料) , 当一个线程B写入成员变量的时候 ,线程B中的本地内存的成员变量的值立刻刷新到主内存中,当线程A要读取线程B的成员变量时,将本地内存的线程B的成员变量内存副本设置为无效,去主线程里面读取(这里也涉及到了 JMM内存模型)。
保证了 防止指令重排序问题,在关于这个变量的操作时候,不能让编译器和处理器进行指令重排序 这样就可以避免这个问题。
代码如下:

public class Test {
    int a = 0;
    volatile boolean flag = false;

    public void writer(){
        a = 1;	//1
        flag =true;	//2
    }

    public void reader(){
        if(flag){	//3
            int i =a*a;	//4
        }
    }
}

那么程序的执行时序图如下在这里插入图片描述
这样就可以让程序正常运行。

PS:
因为这里涉及到线程的相关知识(JMM内存模型,指令重排序,happen-before原则,as-if-serial语义等知识感兴趣的读者可以买一本《Java并发编程的艺术》去看看),所以这篇文章讲的不是很透彻,只是给大家一个解决方案。本文章有若有诸多毛病,请大家包涵

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值