计算机的发展史
最初计算机基于人手工计算(比如算盘)–>后来在计算机中增加机械部件(使用特定的方式表示数字)
电子计算机的出现,用电压的高低压来代替1和0(布尔计算体系),程序通过逻辑门电路执行;
早期,计算机使用的真空管/电子管(在一个真空玻璃管内放置两个电极,通过给阴极电压是温度上升来释放电子,如果阳极处在一个高一点的正电位,电子就会被吸引过去)联通电路,这种单方向的电流是可控的,通过对阴极使用不同的电压,可以是阴极释放不同数量的电子;
然后出现了三极管,使用了第三个点击叫做栅极,这是一种在阴极和阳极之间的网络状线路,可以通过电子,不同的电压可以使它排斥,或者吸引阴极发出的电子,三极管可以方法信号的性能使它成为收音机的关键部位和长距通信,但是真空管不稳定且体型笨重,电子数值积分计算器使用了18000个真空管,体积近似网球场并重达30吨!几乎每天都会出现真空管故障,用电量极高,使用1小时约为15个家庭的日用电量;
后来出现了晶体管,使用半导体来替代电极,晶体管高效,体积小,晶体管不需要加热,耐用,低耗;
如今微芯片携带着几十亿个晶体管,只有指甲盖的大小,每秒万亿次计算!
计算机组成及运算
一次运算的过程:数据存储在内存中,
1.首先将内存中的数据读到寄存器Register中,
2.程序计数器PC读取指令
3.运算单元ALU将寄存器中的数据与程序计数器中的指令进行一系列运算,得到最终结果存储在寄存器中
4.将结果写回内存中
超线程
存储器的层次结构
三层缓存模型,工业测试该模型效率最高
从CPU到存储器的读取速度:
存储位置 | 读取速度 |
---|---|
Register 寄存器 | <1ns |
L1 cache | 约1ns |
L2 cache | 约3ns |
L3 cache | 约15ns |
main memory | 约80ns |
CPU读取速度与到内存读取速度比值约为100:1
即CPU运行100次,内存运行1次
多核CPU
MESI-CPU缓存一致性协议
因特尔CPU使用MESI缓存一致性协议
MESI(Modified Exclusive Shared Or Invalid)(也称为伊利诺斯协议,是因为该协议由伊利诺斯州立大学提出)是一种广泛使用的支持写回策略的缓存一致性协议。
缓存行:
缓存行越大,局部性空间效率越高,但读取时间慢
缓存行越小,局部性空间效率越低,但读取时间快
取一个折中值,目前多用: 64字节
缓存行对齐:对于有些特别敏感的数字,会存在线程高竞争的访问,为了保证不发生伪共享,可以使用缓存航对齐的编程方式
public class Test01_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 < 10_0000_0000L; i++) {
arr[0] = i;
}
});
Thread t2 = new Thread(()->{
for (long i = 0; i < 10_0000_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);
}
}
public class Test02_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 < 10_0000_0000L; i++) {
arr[0] = i;
}
});
Thread t2 = new Thread(()->{
for (long i = 0; i < 10_0000_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);
}
}
测试结果:不使用缓存行对齐,运行10亿次速度约为4600;使用缓存行,运行10亿次速度约为2800;
JDK7中,很多采用long padding提高效率
JDK8,加入了@Contended注解(实验)需要加上:JVM -XX:-RestrictContended
public class Test03_Contended {
@Contended
volatile long x;
@Contended
volatile long y;
public static void main(String[] args) throws InterruptedException {
Test03_Contended t = new Test03_Contended();
Thread t1 = new Thread(()->{
for (long i = 0; i <1_0000_0000 ; i++) {
t.x = i;
}
});
Thread t2 = new Thread(()->{
for (long i = 0; i <1_0000_0000 ; 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);
}
}
参数设置
使用@Contended注解相比不加注解,运算速度快了大约3倍