并发编程系列(五)volatile关键字详解

目录

1. volatile的作用

2. 缓存一致性问题

3. 缓存一致性解决方案

4. volatile原理依赖底层硬件协议(MESI)的实现


序号名称链接地址
1并发编程系列(一)创建线程的三种方式及线程如何完成上下文如何切换https://blog.csdn.net/qq_38130094/article/details/103443997
2并发编程系列(二)之线程的中断https://blog.csdn.net/qq_38130094/article/details/103444171
3 并发系列(三)线程常用的方法https://blog.csdn.net/qq_38130094/article/details/103446126
4并发编程系列(四)之Thread类源码分析(一)https://blog.csdn.net/qq_38130094/article/details/103448160
5并发编程系列(五)volatile关键字详解https://blog.csdn.net/qq_38130094/article/details/103448564
6并发编程系列(六)volatile 之 as-if-serial 指令重排 volatile内存语义 volatile原理https://blog.csdn.net/qq_38130094/article/details/103543998
7线程系列(七)synchronized使用方式https://blog.csdn.net/qq_38130094/article/details/103537663
8 线程系列(八)synchronized实现原理与应用https://blog.csdn.net/qq_38130094/article/details/103537668
9并发编程系列(九)ThreadLocala是如何解决共享变量的并发问题及源码分析https://blog.csdn.net/qq_38130094/article/details/103665098
10并发编程系列(十)AQS同步器独占锁加锁与解锁-源码解读https://blog.csdn.net/qq_38130094/article/details/103540315
11并发编程系列(十一)AQS同步器共享锁加锁解锁源码解读https://blog.csdn.net/qq_38130094/article/details/103646505
12并发编程系列(十二)AQS同步器条件锁(Condition)加锁解锁源码解读https://blog.csdn.net/qq_38130094/article/details/103679146
13发编程系列(十三)ReentrantLock 重入锁https://blog.csdn.net/qq_38130094/article/details/103843779
14发编程系列(十四)Semaphore信号量https://blog.csdn.net/qq_38130094/article/details/103846420
15发编程系列(十五) CountDownLatch闭锁https://blog.csdn.net/qq_38130094/article/details/103855632
16并发编程系列(十六) CyclicBarrierhttps://blog.csdn.net/qq_38130094/article/details/103859704

1. volatile的作用

  1. volatile的作用是保证共享变量的可见性,不能保证原子性,也不能保证线程安全(但是对于单个共享变量的读,写是原子性的)
  2. 可见性:如果某个线程对volatile修饰的共享变量进行更新,那么其他线程可以立刻看到这个更新;
  3. 有序性:禁止指令重排序

在多线程并发编程中sychronized和volatile都扮演着重要的角色,volatile扮演者重要的角色,volatile是轻量级的synchronized,在多处理器开发中保证了共享变量的 “可见性“” 。可见性的意思是当一个线程修改一个共享变量时,另一个线程能读到这个修改的值,如果volatile变量修饰符使用恰当的话,他比synchronized的使用和执行成本更低,因为他不会引起线程上下文的切换和调度


cpu与内存交互

CPU避免和主内存直接打交道,与速度比主内存高出很多的CPU高速缓冲区打交道,充分利用了CPU性能

cpu首先使用自己的寄存器,然后使用速度更快的L1缓存,其中L1D缓存数据;L1l缓存指令;L1缓存和次快的L2做同步数据;

L2缓存和L3按照缓存做同步数据(L2和按照内核数据量做了等分,分给各个内核使用)L3和主内存同步数据

2. 缓存一致性问题

比如说在执行i++

当线程运行这段代码时:

  1. 首先会从主内存读取i(i=1)
  2. 然后复制一份到CPU高速缓存中,CPU在执行+1的操作
  3. 然后将数据+1后的结果写入到高速缓存中
  4. 最后将结果刷新到主存中

这种操作在单线程中没有问题,但是在多线程中会出现问题

如果有两个线程同时在进行这个操作(i++)

  1. Thread1 和Thread2两个线程从主存中读取i的值到各自的高速缓存中,
  2. 然后Thread1执行+1操作并将结果写入到高速缓存中,最终写入到主内存中
  3. 此时主内存i==2,线程Tread2也在做同样的操作,主内存的i值又被更新成2
  4. 所以Thread1和Thread2两个线程执行完毕后,最终结果为2并不是3,与我们的预期值不等

这就是缓存一致性问题

3. 缓存一致性解决方案

1:通过在总线加LOCK#锁的方式:

这是采用了一直这种独占的方式来实现的,即总线加LOCK#锁的话,只能有一个CPU能够运行,其他CPU都要阻塞,来自其他CPU或者总线代理的控制请求将会阻塞,效率很低(其他CPU会出现假死的情况)。

2:缓存一致性协议【嗅探技术+MESI协议】

“嗅探” 的基本思想就是在所有内存传输都发生在一条共享的总线上,所有的CPU都能看到这总线。

缓存本身是独立的,但是内存是共享资源的,所有内存访问都要经过仲裁(arbitrate):同一个指令周期中,只有一个缓存可以读写内存,嗅探的技术思想就是,缓存不仅仅在做内存传输的时候才和总线打交道,而是不停的在窥探总线上发生的数据交换,跟踪其他缓存在做什么,所以当一个缓存代表他所属的CPU去读写内存时,其他CPU都会得到通知,他们以此来使自己的缓存保持同步,只要某个cpu一写内存,其他CPU马上就知道这块内存在他们的缓存中对应的缓存行已经失效

MESI协议:

1、修改(Modified)高速缓存行仅存在于当前高速缓存中,并且是脏的 - 它已从主存储器中的值修改(M状态)。在允许对(不再有效)主存储器状态的任何其他读取之前,需要高速缓存在将来的某个时间将数据写回主存储器。回写将该行更改为共享状态(S)。

2、独家(Exclusive)缓存行仅存在于当前缓存中,但是干净 - 它与主内存匹配。它可以随时更改为共享状态,以响应读取请求。或者,可以在写入时将其改变为修改状态。

3、共享(Shared)表示此高速缓存行可能存储在计算机的其他高速缓存中并且是干净的 - 它与主存储器匹配。可以随时丢弃该行(更改为无效状态)。

4、无效(Invalid)表示此缓存行无效(未使用)

 

4. volatile原理依赖底层硬件协议(MESI)的实现

1

只会锁定工作内存

通过总线裁决保证只有一个变量能够被修改成功

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值