美文网首页
线程安全:可见性(gold_axe)

线程安全:可见性(gold_axe)

作者: 胖达_4b7e | 来源:发表于2020-02-05 17:08 被阅读0次

    https://book.douban.com/subject/27034721/

    可见性 有问题就是: 某些线程读到了过期的数据, 导致程序错误

    原因

    一. JIT 优化

    比如 这个

      @Override
      public void run() {
        while (!toCancel) {
         //......没有对toCancel更新代码
          }
        }
    

    会被JIT编译器优化为

     @Override
      public void run() {
        if (!toCancel){
          while (true){
            //...
          }
        }
    

    因为JIT编译器 ,默认代码是为单线程而写的, 他会觉得:

    既然while里面不去改toCancel, 那toCancel就是不变的 , 不变的东西在循环里面一遍遍取重复检查 就是浪费, 只要检查一遍就好了啦, 我给你改一改, 意思是完全一样的!

    二.存储

    1.每个cpu都有其寄存器
    如果,2个线程在2个cpu上各自运行,变量被分配到其寄存器, 而不是主内存存储,就读不到另一个线程的变量了

    2.高速缓存子系统
    即使,没有被分配到寄存器,
    处理器对主内存不是直接访问,而是通过高速缓存子系统, 一个cpu上对变量的更新,可能只到这个cpu的写缓冲器, 没有到达这个cpu的高速缓存, 更加没到 主内存

    3.其他cpu没更新
    即使,写入了这个cpu的高速缓存
    cpu会把这个变量更新的通知给其他cpu,
    但是其他cpu , 收到通知, 可能只是把 自己的这个变量加入 无效化队列
    并没有 直接根据通知内容 更新其高速缓存 相应变量

    保证可见性

    在声明变量的时候 加个 volatile

    1.JIT编译器 , 看到这个 就知道这个变量会被多个线程共享, 不会再认为就一个线程会访问
    2.cpu 这个变量的时候, 会 刷新处理器缓存, 这个变量的时候, 会冲刷处理器缓存

    刷新处理器缓存:
    从其他处理器的高速缓存或者主内存中, 对本线程也用到的变量 全部进行缓存同步

    冲刷处理器缓存:
    使对处理器对共享变量的更新 全部 最终写入该处理器的高速缓存或者主内存, 而不是停留在其写缓冲区, 让其他处理器可同步

    加锁(内部锁,显示锁都行)

    除了保证原子性外, 也能保证可见性,

    因为

    • 获取锁的时候 刷新了处理器缓存(本线程更到最新)
    • 释放锁时 冲刷处理器缓存(推送本线程的更新到高速缓存)

    Java 语言规范 对父子线程的可见性保证

       // 在子线程thread启动前更新变量data的值
        data = 1;// 语句① 父线程赋值
        thread.start();//子线程在其后开始, 保证能看到
    

    语句① 的改动, 在子线程里面可见

     thread.join();
     // 读取并打印变量data的值
     System.out.println(data);
    

    thread子线程结果以后, 它对data的修改, 其主线程 能看到

    相关文章

      网友评论

          本文标题:线程安全:可见性(gold_axe)

          本文链接:https://www.haomeiwen.com/subject/tjbsxhtx.html