读书的原则:不求甚解,观其大略
本质:一堆沙子 + 一堆铜 + 一堆胶水 + 特定金属添加 + 特殊工艺
沙子脱氧 ->石英 ->二氧化硅 ->提纯 ->硅锭 -> 切割->晶圆 -> 涂抹光刻胶-> 光刻-> 蚀刻->清除光刻胶 ->电镀 -> 抛光-> 铜层-> 测试->切片 ->封装
Intel cpu的制作过程(视频描述)
cpu是如何制作的(文字描述)
cpu内部:硅-> 加入特殊元素->P半导体 N半导体 -> PN结->二极管 ->场效应晶体管 -> 逻辑开关
基础逻辑电路:与门 或门 非门 或非门(异或) 加法器 累加器 锁存器 …
实现手动计算(每次读取内存指令,(高电低电))
推荐书籍:《编码》17章
对于cpu运算是通过高电频,低电频->转换成逻辑上,就为二进制数字:0,1->告诉计算机哪个针脚该通断电
手工输入:纸带计算机
助记符:01000010->mov sub……
高级语言->编译器->机器语言
计算机需要解决的最根本问题:如何代表数字
晶体管是如何工作的
晶体管的工作原理
汇编的本质:机器语言的助记符,其实它就是机器语言:mov sub add代表二进制数据
过程:计算机通电 -> CPU读取内存中程序(电信号输入)->时钟发生器不断震荡通断电 ->推动CPU内部一步一步执行(执行多少步取决于指令需要的时钟周期)->计算完成->写回(电信号)->写给显卡输出(sout,或者图形)
PC -> Program Counter 程序计数器 (记录当前指令地址)
Registers -> 寄存器:暂时存储CPU计算需要用到的数据
ALU -> Arithmetic & Logic Unit 运算和逻辑单元
CU -> Control Unit 控制单元 中断信号的控制
MMU -> Memory Management Unit 内存管理单元–硬件+os实现
超线程:一个ALU对应多个PC|Register
所谓的四核八线程 如图:
按块读取
缓存最基本原理:程序局部性原理,可以提高效率
充分发挥总线CPU针脚等一次性读取更多数据的能力
为了保证数据的一致性:以缓存行为单位,定义了四种缓存行状态
一致性协议
缓存行:目前工业上来说三级缓存最合适
缓存行越大,局部性空间效率越高,但读取时间慢
缓存行越小,局部性空间效率越低,但读取时间快
取一个折中值,目前多用:64字节
同一缓存行1亿次赋值执行效率 volatile保证线程之间的可见性
package com.mashibing.juc.c_028_FalseSharing;
public class T03_CacheLinePadding {
public static volatile long[] arr = new long[2];
public static void main(String[] args) throws Exception {
Thread t1 = new Thread(()->{
for (long i = 0; i < 10000_0000L; i++) {
arr[0] = i;
}
});
Thread t2 = new Thread(()->{
for (long i = 0; i < 10000_0000L; i++) {
arr[1] = i;
}
});
final long start = System.nanoTime();
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println((System.nanoTime() - start)/100_0000);
}
}
不同缓存行1亿次赋值执行效率
package com.mashibing.juc.c_028_FalseSharing;
public class T04_CacheLinePadding {
public static volatile long[] arr = new long[16];
public static void main(String[] args) throws Exception {
Thread t1 = new Thread(()->{
for (long i = 0; i < 10000_0000L; i++) {
arr[0] = i;
}
});
Thread t2 = new Thread(()->{
for (long i = 0; i < 10000_0000L; i++) {
arr[8] = i;
}
});
final long start = System.nanoTime();
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println((System.nanoTime() - start)/100_0000);
}
}
结果很明显地看出使用不同缓存行的执行速度更快
因此诞生了一种编程模式——缓存行对齐
缓存行对齐:对于有些特别敏感的数字,会存在线程高竞争的访问。为了保证不发生伪共享,可以使用缓存行对齐的编程方式。
比如disruptor前后都填充7个long类型数据保证独立缓存行:
JDK7中,很多采用long padding提高效率
JDK8,加入了@Contended注解(实验)需要加上:JVM -XX:-RestrictContended
package com.mashibing.juc.c_028_FalseSharing;
import sun.misc.Contended;
/**
* T05_Contended
* Description
*
* @date 2020/5/26 - 23:38
*/
public class T05_Contended {
@Contended
volatile long x;
@Contended
volatile long y;
public static void main(String[] args) throws InterruptedException {
T05_Contended t = new T05_Contended();
Thread t1 = new Thread(()->{
for (long i=0;i<1_0000_0000L;i++){
t.x=i;
}
});
Thread t2 = new Thread(()->{
for (long i=0;i<1_0000_0000L;i++){
t.y=i;
}
});
final long start = System.nanoTime();
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println((System.nanoTime() - start)/100_0000);
}
}