CPU原理图简概和缓存架构图(Volatile底层)&&并发编程-JMM模型&&DCL的volatile
2021-01-11 11:52:49 1 举报
CPU原理图简概和缓存架构图(Volatile底层)&&并发编程-JMM模型&&DCL的volatile
作者其他创作
大纲/内容
L2 Cache
private void write(String s) { try { synchronized (this) {
CPU的运行原理就是:控制单元在时序脉冲的作用下,将指令计数器里所指向的指令地址(这个地址是在内存里的)送到地址总线上去,然后CPU将这个地址里的指令读到指令寄存器进行译码。对于执行指令过程中所需要用到的数据,会将数据地址也送到地址总线,然后CPU把数据读到CPU的内部存储单元(就是内部寄存器)暂存起来,最后命令运算单元对数据进行处理加工。周而复始,一直这样执行下去。
L3 Cache
ThreadB
CPU中有时钟周期的概念,CPU执行一行指令就是一个时钟周期。
while(true)有个底层算法,会优先抢占时间片,一直占用资源执行
进程
use指令
数据
控制单元
数据1...数据m
flag=true
主内存
指令
L1 Cache
CPU1(双核)
主内存RAM
write指令刷到主内存
指令1...指令n
load指令加载到本地内存进行初始化
一般电脑都是单CPU多核多逻辑处理器
flag=false
本地内存
CPU1
寄存器
CPU原理图简概和缓存架构图(Volatile底层)&&并发编程-JMM模型&&DCL的volatile
assgin指令用来回写修改的变量
assgin指令
也可以在while方法中加上一个打印语句,也可以跳出循环。原因是println和print底层是用synchronized锁住当前线程,synchronized会保证进入synchronized代码块之前的线程的,对共享变量的可见性,其他线程修改后的值是对线程A可见的。
操作数地址
运算单元
变量
指令寄存器
CPU Core2
通过use指令将本地内存中变量flag的值读取到CPU寄存器,执行代码逻辑:while(true)
public class Test {private static volatile int sum=0; /**如果用10或100这种小量的可能会出现结果准确 * 循环创建100个线程,每个线程执行100次sum++:单线程执行结果为1000000 * 但是多线程呢?不加volatile,结果肯定是小于1000000. * 但是为sum加上volatile,只能保证sum的可见性(缓存一致性), * 却会因为缓存一致性机制的MESI协议 * 导致部分sum++无效执行,结果还是小于1000000 */ public static void main(String[] args) { for (int i = 0; i < 1000; i++) { Thread thread=new Thread(()->{ for (int j = 0; j < 1000; j++) { sum++; } }); thread.start(); }// for (int i = 0; i < 100; i++) {// for (int j = 0; j < 100; j++) {// sum++;// }// } System.out.println(\"换行\"); System.out.println(\"sum=\"+sum);//最终的结果还是不准确 try { Thread.currentThread().sleep(1000L); System.out.println(\"sleep=\"+sum);//循环次数小线程少的时候准确 } catch (InterruptedException e) { e.printStackTrace(); } }}
CPU
CPU Core1
public void println(String x) { synchronized (this) { print(x); newLine(); } }
如何保证数据一致性:锁总线,如何cpu修改数据都通过锁总线的方式来保证数据一致性。但是这样相当于单线程执行。因此演化出缓存一致性机制。缓存一致性机制有很多种协议,目前大多数CPU都遵从的是MESI(M:修改、E:独占、S:共享、I:无效),通过缓存行锁和总线嗅探机制来完成。
DCL(double check) 双重校验锁 为何用 volatile
指令地址
CPU2(双核)
CPU1 Core1
store命令回写
Volatile底层
read指令读取出来
volatile底层就是通过lock指令触发缓存一致性协议,按上面的MESI协议保证多线程的共享变量可见性。
数据段
最佳方案:直接给flag加volatile,保证共享变量的线程间的可见性
多线程共享变量JMM流程图
CPU2 Core1
存储单元
CPU缓存架构
变量副本
多cpu和多核架构图:
while(flag){......}
内存
JSR133定义的规范,JMM描述的是一种抽象的概念,一组规则,通过这组规则控制程序中各个变量在共享数据区域和私有数据区域的访问方式,JMM是围绕原子性、有序性、可见性展开的
代码段
但是刷到主内存后,线程A一直占用着时间片,所以A一直是从本地内存读取的。如果线程A执行sleep,线程休眠一段时间后,线程A就会让出时间片,如果时间够长本地缓存就会失效,这样线程A就会重新从主内存中读取,这样才能读取到修改后的flag的值。
ThreadA
指令计数器
CPU原理图简概
以双线程并发举例:
0 条评论
下一页