IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> volatile关键字是怎样实现的 -> 正文阅读

[Java知识库]volatile关键字是怎样实现的

理解volatile关键字可以分为两块,一块是它到底是怎么实现功能的,另一部分就是Java内存模型中volatile的内存语义。前者是变量加上volatile之后,处理器和编译器会怎样的处理,后者是在整个Java程序中,添加了volatile之后,编译器会保证volatile这一块不会被重排序。点击查看Java内存模型

Java语言对volatile的定义:Java 编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。volatile又被称为轻量级的synchronized,但是volatile并不需要加锁,它没有线程上下文的切换和调度,比synchronized的使用成本更低。

volatile保证可见性,但是不保证原子性,JMM会防止对volatile的执行重排。

可见性

每个线程都有自己的工作内存(寄存器、高速缓存组成),线程之间是通过主内存进行通信。即线程A把从主内存读取,然后进行运算,将运算后的结果从自己的工作内存写回到主内存,当线程A写回完成之后,其他线程再去主内存读取,就可以得到线程A处理的结果,完成通信。但是,线程A不会经常回写主内存,不然的话处理速度就慢死了,不回写其他的线程就看不到处理之后的数据,只能得到之前的数据。线程看到的数据不一致,就造成可见性问题。

计算机的处理器运行速度要比内存的读取速度快好几个数量级。但是整个运算流程必须是先从内存中读取某个数据,然后交给处理器,随后将结果再写回到内存中。如果这样的话整个运行的速度就会被卡在内存上,内存读取有多快整体运算有多快,就算处理器再好也没用。巧妇难为无米之炊,从内存读取的数据就是处理器需要的米。遇到海量高并发的时候有个统一思想,异步缓存批量处理。这里采用的就是批量处理,直接从内存中读取一批数据,然后统一交给处理器处理,等处理完成之后统一写回到内存中。

所以普通的数据是不会立即写回到主内存中的,而是先保存在工作内存中。但是如果用volatile修饰,会让工作内存立即写回到主内存或者从主内存中重新读取,保证数据的可见性。

Lock前缀

有 volatile 变量修饰的共享变量进行写操作的时候会多出一行汇编代码,且是Lock指令开头。Lock 前缀的指令在多核处理器下会引发了两件事情:
1.将当前处理器缓存行的数据写回到系统内存。
2.这个写回内存的操作会使在其他 CPU 里缓存了该内存地址的数据无效。

Lock前缀指令导致在指令执行期间,声言处理器的LOCK#信号,LOCK#信号会保证在声言此信号期间,处理器可以独占任何共享内存。一部分处理器是通过锁住总线,总线控制读写,锁住总线意味着其他的处理器没有办法访问共享内存,此时只有当前的处理器可以访问内存,实现了独占共享内粗功能。但是锁住总线的代价是很大的,所以另一部分处理器采取的是锁住缓存,如果要写入的内存区域已经缓存在处理器内部,则不会声言LOCK#信号,而是锁定内存区域的缓存并将他写回到内存中,并使用缓存一致性机制来确保修改的原子性,此操作被称为“缓存锁定”,缓存一致性机制会阻止同时修改由两个以上处理器缓存的内存区域数据。

当一个处理器缓存写回到内存时,其他处理器的中此缓存数据将无效。每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是否过期,当处理器发现自己缓存行对应的总线地址被修改,就会将当前处理器的缓存设置为无效,当处理器需要此数据时,会重新从共享内存中读取。

缓存一致性机制:总线加锁是对整个共享内存,此时其他的处理器无法从共享内存读取数据,会严重降低CPU的处理能力。缓存一致性协议只会对单个缓存行的数据进行加锁,不会影响到内存中其数据的读写。缓存一致性协议有:MSI、MESI、MOSI等。MESI协议只对汇编指令中执行加锁操作的变量有效,表现到java中为使用voliate关键字定义变量或使用加锁操作。

MESI协议有四种状态:修改、独占、共享、无效
在这里插入图片描述
大致流程如下:
1.线程A读取数据Q,将数据Q的状态设置为E(独享、互斥),同时通过总线嗅探机制对共享内存中的数据Q进行嗅探

2.线程B再次读取数据Q, 总线嗅探将线程A中的Q设置为S(共享),线程B的Q状态也是S共享

3.线程A修改数据Q, 线程A中的状态变为M(修改),而线程B将会被通知修改为I(无效)。无效的数据将不会被操作,需要从共享内存中重新读取。如果有多个线程同时修改Q,那么总线会进行裁决,某一个变为M,其他的都变为I。

4.线程A将Q回写内存,此时状态变为E(独占),因为只有他时新数据,其他线程都无效,相当都独享。

5.线程B通过总线嗅探机制得知Q已经回写到内存,重新读取Q,状态为S,同时线程A中的状态也变成S。

参考阅读

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-11-20 18:15:31  更:2021-11-20 18:17:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:03:00-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码