java线程可见性

2020-02-08  本文已影响0人  我不知道得真多

一、概念层面的可见性

什么是线程间的可见性?
一个线程对共享变量值的修改,能够及时的被其他线程看到。

    public class App {
    public static boolean  stop = false;

    public static void main(String[] args)  throws InterruptedException  {

        Thread t1 = new Thread(()->{

           int  i = 0; 

           while(!stop){

               i++;

           }

        });

        t1.start();

        Thread.sleep(1000);

        stop = true;
    }
}

上面代码运行会发现,stop 就算值已经被修改了。也没有办法,

线程也不会读取到,程序处于死循环之中,不会退出。

引出下面问题,线程可见性及其基本原理

如果添加了 volatile 情况就会不一样

public  volatile  static boolean  stop = false;

线程保证可见性

1.volatile 保证了线程可见性
2.多了一个Lock 的汇编指令

可见性到底是什么?两个层面分析

CPU 内存、 I/O 设备 读取速度差异

为了最大化利用CPU资源

  1. CPU增加高速缓存
  2. 引入线程、进程
  3. 指令优化 - > 重排序

二、CPU高速缓存,缓存导致不一致问题

cpu层面解决

  1. 总线锁 (总线上加锁,效率低)
  2. 缓存锁 (优化后)

基于MESI 协议可以解决缓存一致性的问题

MESI 表达缓存数据的四种状态
m : modify 、 e : exclusive 、 s :shared 、 i : invalid

MESI表达缓存数据

MESI协议带来的问题 (CPU 通信)

MESI协议带来的问题

cpu 在读缓存过程中,发送消息给其他cpu 时候其他cpu 缓存失效并且在发

送指令给,读取cpu 中,这段时间读取缓存CPU需要阻塞,否则无法保证

缓存一致性,这样也会导致CUP利用率不够。

提出解决方案storebuffer 存储缓冲

比如你需要修改本地缓存中的一条信息,那么你必须将I(无效)状态通知到其他拥有该缓存数据的CPU缓存中,并且等待确认。等待确认的过程会阻塞处理器,这会降低处理器的性能。因为这个等待远远比一个指令的执行时间长的多。当所有失效确认(Invalidate Acknowledge)都接收到时,数据才会最终被提交。
这么做有也有风险,这里不作讨论

硬件内存模型

上一篇 下一篇

猜你喜欢

热点阅读