线程安全之可见性杂记

public static boolean flag =false;

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            int i = 0;
            while (!flag){
                i++;
            }
            System.out.println(i);
        });
        thread.start();
        Thread.sleep(1000);
        flag = true;
    }

不会停止运行,也没有打印出i的值。
深度优化,编译器会对程序进行优化。
while (!flag){ i++; } ——> if(!flag){while(true){i++}
改变了flag的值,也不会停止while循环。
在while循环中加上print语句或者sleep能够停止,活性失败。print中包含IO操作和synchronized,锁的释放会将线程工作内存中写的操作同步到主内存中。如果在while循环中添加锁操作(有释放锁的操作),下次循环会去读取最新的flag值。IO操作同样可以(具体原因不清楚)。sleep操作,猜想是时间片的切换,重新竞争CPU资源导致的缓存行失效。

volatile关键字。保证可见性,一定的有序性,不保证原子性。

硬件层面。CPU高速缓存,总线锁,缓存锁(缓存一致性协议)
MSI、MESI、MOSI
MESI:Modify(修改)、Exclusive(独占)、Shared(共享)、Invalid(失效)
优化MESI,引入store buffer,异步对缓存行中数据的写操作,通知其他CPU缓存行失效后才执行写操作。会导致有序性问题,指令重排序。
内存屏障,同步到主内存,防止指令重排序。

Happens-Before模型
程序顺序规则(as-if-serial语义)
  • 不能改变程序的执行结果(在单线程环境下,执行结果不变)
  • 依赖问题,如果两个指令存在依赖关系,是不允许重排序的
传递性规则
volatile变量规则
监视器锁规则
start规则
  • 线程启动前的数据对于启动的线程是可见的
Join规则
  • 线程调用join()执行完之后的数据对于join()之后的数据访问是可见的
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值