JMM基础-计算机原理
| 操作 | 响应时间 |
|---|---|
| 打开一个站点 | 几秒 |
| 数据库查询一条记录(有索引) | 十几毫秒 |
| 1.6G的CPU执行一条指令 | 0.6纳秒 |
| 从机械磁盘顺序读取1M数据 | 2-10毫秒 |
| 从SSD磁盘顺序读取1M数据 | 0.3毫秒 |
| 从内存连续读取1M数据 | 250微秒 |
| CPU读取一次内存 | 100纳秒 |
| 1G网卡,网络传输2kb数据 | 20微秒 |
| 1秒 = 1000毫秒 1毫秒 = 1000微秒 1微秒 = 1000纳秒 | |
物理内存模型带来的缓存问题
多核CPU处理程序时,每个CPU都有自己的高速缓冲区。
CPU A和B同时执行:
1、执行步骤1,CPU A将a = 1写入缓冲区,CPU B将b = 1写入缓冲区;
2、执行步骤2,CPU A读取主内存,读到结果b = 0; CPU B读取主内存,读到结果a = 0;
3、执行步骤3,CPU A将a = 1刷新到主内存,CPU B将b = 1刷新到主内存;
4、执行步骤4,CPU A将读取的b = 0赋值给x,所以x = 0;
CPU B将读取的a = 0赋值给y,所以y = 0;
5、执行结束前,CPU A将x = 0刷到主内存;
CPU B将y = 0刷到主内存;
伪共享
CPU是以缓存行为单位读写的,每个缓存行大小为64byte。
所以缓存行是CPU最小的缓存单位。
long类型占用8byte(64位)。
假如x和y正好写在同一个缓存行上,这时候CPU A要访问x,CPU B要访问y。看似两个CPU读取的不同的对象应该不会涉及关联,但由于x和y存储在同一缓存行上导致产生了竞争,这就是伪共享现象,对性能有影响。
防止缓存行的竞争,可以填充补位
disruptor高速队列就是采用了补位来提升性能(百万级吞吐量:无锁化读写,环形队列避免GC,避免伪共享)
/** * jdk8新特性,Contended注解避免false sharding * Restrict on user classpath * Unlock: -XX:-RestrictContended */ @sun.misc.Contended public final static class VolatileLong { public volatile long v = 0L; }Java内存模型(JMM)
工作内存=共享变量的副本
工作内存是抽象的一个概念,并没有实际对应的硬件来呈现它。
JMM导致的并发安全问题
可见性问题:
线程1读取主内存count值到工作内存副本中,值为1,进行++操作;
线程2读取主内存count值到工作内存副本中,值可能也为1,因为线程1同步主内存时间不确定。
可以使用volatile和锁解决可见性问题。
竞争(原子)问题:
线程1,线程2读取主内存count值,分别进行++操作;
最终主内存count值应该为3(由于每个线程读取到的count=1,++操作后count=2,最终线程会将2刷回主内存);
可以使用锁来解决,将线程的并行操作改为线性操作。
Java内存模型中的重排序
重排序类型
重排序与依赖性
| 名 称 | 代码示例 | 说 明 |
|---|