无名商城论坛

搜索
查看: 249|回复: 0

[其他技术] 【LSP】并发编程之volatile

[复制链接]

1万

主题

1万

帖子

3万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
32464
发表于 2022-5-8 17:04:17 | 显示全部楼层 |阅读模式


一、Java内存模型内存交互操作
1、lock(锁定):作用于主内存的变量,把一个变量标记为一条线程独占状态

2、unlock(解锁):作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定

3、read(读取):作用于主内存的变量,把一个变量值从主内存传输到线程的工作内存中,以便随后的load动作使用

4、load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中

5、use(使用):作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎

6、assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量

7、store(存储):作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作

8、write(写入):作用于工作内存的变量,它把store操作从工作内存中的一个变量的值传送到主内存的变量中

整个执行流程如图





read ---load  store----writr必须成对执行

通过上面分析我们可以看出即使在java里面执行i++这样的操作,对于我们的底层来说也不是原子操作,因为i++,也需要将这八大操作走一遍,具体来说,read ---load 将主内存中i=0在工作内存中也copy一份,

线程读到工作内存中的i=0并加1操作即结果i=1写回工作内存(use---assign),然后将i=1写回主内存(store----writrt)这一步如果没有用缓存一致性协议,会有延时不会立即写到主内存,参考第一篇缓存一执行性协议讲解。

二、volatile原理与内存语义
volatile是Java虚拟机提供的轻量级的同步机制

volatile语义有如下两个作用

可见性:保证被volatile修饰的共享变量对所有线程总数可见的,也就是当一个线程修改了一个被volatile修饰共享变量的值,新值总是可以被其他线程立即得知。

有序性:禁止指令重排序优化。

volatile缓存可见性实现原理

JMM内存交互层面:volatile修饰的变量的read、load、use操作和assign、store、write必须是连续的,即修改后必须立即同步会主内存,使用时必须从主内存刷新,由此保证volatile变量的可见性。 底层实现:通过汇编lock前缀指令,它会锁定变量缓存行区域并写回主内存,这个操作称为“缓存锁定”,缓存一致性机制会阻止同时修改被两个以上处理器缓存的内存区域数据。一个处理器的缓存回写到内存内存会导致其他处理器的缓存无效

三、volatile可见性分析
先上一段代码:
测试结果:加锁会导致线程B失去cpu执行权,当再次获取cpu执行权时,会引起线程上下文切换,这个过程会引起重新读取主内存数据。

volatile关键字测试

initFlag用volatile修饰后

private volatile boolean  initFlag = false;
测试结果:当线程A修改initFlag后线程B能立即感知到,停止循环打出标志语;

原因:线程A修改initFlag,由于initFlag被volatile修饰,会立即从工作内存刷到主内存,同时让其他线程中工作内存中initFlag数据缓存失效,这样线程B中原来地缓存失效,从主内存中重新读取新值。

四、volatile不能保证原子性
先来一段代码:
开10个线程每个线程对counter进行1000次+最总我们地结果也不是10000,而是小于10000,

原因:couter++并不是原子操作,比如两个线程读到counter=0都读到自己地工作内存,然后加1之后都要往我们地主内存写,这时候必然引起裁决,导致一个线程的+1有效果,一个线程的+1无效果,最后导致

两个线程一共加了两次1,只有一个有效,最后结果比预期结果小。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表