线程安全性 - 可见性volatile

线程安全性 - 可见性

在这里插入图片描述

可见性 - synchronize

在这里插入图片描述

可见性 - volatile

volatile可见性的实现:
通过内存屏障禁止重排序优化来实现;

1.volatile变量写操作时,会插入一条store屏障指令(StoreStore和storeLoad),将本地内存中的共享变量值刷新到主内存; (store,load是jmm 指令,参考:https://blog.csdn.net/wangnanwlw/article/details/86466782)

2.对volatile变量读操作时,会在读操作前加入一条load屏障指令(LoadLoad和LoadStore),从主内存中读取共享变量。

通俗的说,volatile变量在被线程访问时,都是从主内存中读取,而当该变量发生变化时,会强迫变量刷新回主内存,这样任何时候,不同的变量都可以看到volatile变量的最新值。

在这里插入图片描述

可见性 - volatile写

volatile 写操作插入屏障的示意图:
1.在volatile写操作时,会先在volatile写之前插入一个StoreStore屏障,作用是:禁止上面的普通写和下面的volatile写重排序;

2.在volatile写操作时,会在volatile写之后插入一个StoreLoad屏障,作用是:防止上面的volatile写与下面可能的volatile读/写重排序;

在这里插入图片描述

可见性 - volatile读

volatile 读操作插入屏障的示意图:
1.在volatile读操作时,会先在volatile读之后插入一个LoadLoad屏障,作用是:禁止下面的普通读操作和上面的volatile读重排序;

2.接下来,会在LoadLoad屏障之后插入一个LoadStore屏障,作用是:禁止下面所有的写操作与上面的volatile读重排序;

在这里插入图片描述

所有 屏障指令都是在CPU级别指令进行操作的,volatile 具有可见性

volatile 适合的场景

volatile不适合计数场景

在这里插入图片描述
执行结果:
5000
4998
4993
结果不一定,不是线程安全,volatile不适合计数场景

volatile使用应具备两个条件

1、对变量写操作不依赖于当前值 ,
2、该变量没有包含在具有其他变量的不变式中.

使用场景:1、适合状态标记量,例子:

用volatile标识线程是否初始化,初始化以后再进行后续操作

在这里插入图片描述

使用场景:2、double check(检查两次)

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/wangnanwlw/article/details/86467987