美文网首页
线程安全:可见性(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