从操作系统到volatile

操作系统:
 
计算机程序运行:
 
进程:QQ.exe双机之后加载到内存,分配资源的最基本单位。
运行:CPU从内存中找到程序的main函数开始的位置把指令和数据读出来,把数据放在registers,把指令用pc保存起来,读一条指令执行一条指令。
多线程:进程运行的时候,程序的主线程和fork出来的子线程一起执行。
线程:资源调度的基本单位。
alu计算单元:保存现场到cache
线程切换:单核cpu,第一个线程执行,时间片到了之后,alu会把现场存储在cache中,切换第二个线程。如果再切换回来第一个线程,就用cache恢复现场继续执行。
注意:io中不占用cpu,只有计算才使用cpu。
摩尔定律:CPU18个月性能增强一倍
线程撕裂者(超线程):一个计算单元对应两组或多组寄存器
线程可见性:
CPU速度比内存快100倍,所以在Cpu和内存之间有多级缓存,每个核有两个缓存。每CPU有一个多核共享缓存。
局部性原理:空间局部性和时间局部性。CPU在读取内存的时候会一次卖取一块数据,或叫一行数据cacheline作为缓存,工业标准大小是64个字节。
缓存一致性协议:当某一个cpu修改了缓存行中某个数据的时候,就要通知其他的cpu改变缓存行.
保证可见性:volatile
volatile修饰的内存的修改会通知所有用到这块内存的所有线程重新读取
线程有序性:
指令重排序:单线程中的指令看上去是顺序执行的,实际未必(as-if-serial).
指令重排序原因:提高执行效率,压榨CPU,流水线执行,提高CPU效率.
什么情况下可以重排序:指令乱序之后不影响最终一致性(不论指令如何乱序都不会影响最终结果).
指令重排序后果:会产生不希望看到的结果
对象创建过程:new一块内存空间设置默认值->构造方法设置初始值->栈中指针和堆中对象建立关联
 
sychronized:
临界区:被sychronized修饰的方法区或代码区
*将多线程变成单线程线性执行
*临界区应该尽可能的小
DCL单例(double check lock):判断是否为空->上锁->再次判断是否为空
DCL单例是否需要volatile?
第一个线程执行的之后遇到了指令重排,出现了半初始化对象,第二个线程判断instance不是空的,但其实没有初始化完成
sychronized保证线程有序性,不保证语句有序性
哪些指令可以重排:8种happens-before
 
volatile怎么阻止指令重排的:
JVM规定,fence/barrier上面和下面的指令不能换顺序(内存屏障),每个CPU有不同的屏障指令,JVM有四条屏障:
LoadLoad读读
StoreStore写写
LoadStore读写
StoreLoad写读
指的是fence/barrier的上面的Load,下面是Store的时候算是屏障
执行过程是如图
上面的Load操作读取了右侧数据,下面的Load也读取了右侧数据的时候,中间加LoadLoad.虚拟机发现了这种情况的时候就会阻止指令重排
*不用volatile修饰,就不加
volatile加屏障的原理
 
 
底层位置:

orderaccess_linux_x86.inline.hpp

inline void OrderAccess::fence() {
  if (os::is_MP()) {
    // always use locked addl since mfence is sometimes expensive
#ifdef AMD64
    __asm__ volatile ("lock; addl $0,0(%%rsp)" : : : "cc", "memory");
#else
    __asm__ volatile ("lock; addl $0,0(%%esp)" : : : "cc", "memory");
#endif
  }
}

 

 
 
 
 
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值