多线程与高并发
可见性
一个程序是怎么跑的?
内存里,语句构成。被操作系统读进cpu里,去执行。
cpu比内存快100倍。
于是存在缓存。
cpu:寄存器,ALU,
多级缓存的架构?有利有弊
三级缓存比较合适
找数据,先从L1找,有就返回,没有就L2,L3。 还是没有的话,从内存中读,放在L123中。
局部性原理
取大块的数据: 命中率比较高,消耗的资源比较高。
取小块的数据:低,低
合适的大小: 8个或64个字节(缓存行)
有6个备份
左边的改了数据,怎么通知右边的?
在所有的机器里面必须拥有一种机制来进行数据同步
所有的硬件都有缓存一致性协议
英特尔中是 MESI
还有就是 MOSI
不在一个缓存行,避免了缓存一致性
在一个缓存行的话,每做一个修改,要通知其他cpu中的缓存修改。
链表头指针,尾指针。
环形缓存区,只需要一个指针
由于缓存一致性,所以放了7个数据。
他的父类,也就是前面有7个。
不会和其他有用的数据在同一行,避免把时间浪费在缓存一致性上。
用空间换时间
有序性
结论:单线程里 ,看到的执行顺序和 实际执行的顺序 有可能不一样。
面试题1
可能发生乱序,run线程会打印0;
面试题:this溢出问题
理论上 不一定是8,有可能是0;
汇编码:
1: new 申请一块空间,java默认值是0或者null
4 : 调用构造方法,才能变为8
7: 将t指针指向 这块空间
7跑前面去了
不可以在构造方法里启动线程
加问DCL要不要加volatile问题?
DCL:double check lock 双重检测锁
外面的if有没有必要:有,因为没有的话,所有线程都需要锁竞争,效率太低了。
要不要加volatile?
第一个线程
换了顺序
正好第二个线程来了,判断不等空,就没有
问题: 为什么能访问第一个线程的中间状态?
是线程2的第一个if的访问,非上锁的代码可以访问上锁的代码的中间态。
上锁不能保证有序性。
为什么要有重排序?
提升效率,
取数据100ns
++操作1ns
不排序 101ns
++前 100ns
什么情况下能重排?什么情况下不能重排?
程序判断。
不影响结果一致性就可以换。
如何控制乱序?
乱序在单线程里没有问题
as-if-serial:看上去像序列化
happens-before原则:jvm级别的保障,八条原则,
如何不换顺序:通过内存屏障
屏障指令,前后的语句不会换顺序。
屏障
jvm级别的屏障
要不要加volatile?
就加了屏障,
所有的写操作前面有SS,后面有SL
所有的读操作后面有LL和LS。
cpu级别的屏障