第1章走进并行的世界
1.2你必须知道的几个概念
1.2.1 同步和异步
1.2.2 并发和并行
1.2.3 临界区
临界区:用来表示一种公共资源可以被多个线程使用。但是每一次,只有一个线程可以使用它。
1.2.4 阻塞和非阻塞
1.2.5 死锁(Deadlock),饥饿(Starvation)和活锁(Livelock)
饥饿(Starvation):指某一个线程或者多个线程因为种种原因无法获得所需的资源,导致一直无法执行。
活锁(Livelock):两线程互相谦让。主动释放资源给它人使用,那么就会出现资源不断地在两个线程之间跳动,导致没有一个线程可以拿到所有资源而正常执行。
1.3 并发级别
1.3.1 阻塞
1.3.2 无饥饿
与线程优先级有关(公平与非公平锁)
1.3.3无障碍
无障碍是一种最弱的非阻塞调度。
两线程公共进入临界区:
修改共同资源:回滚;
没修改共同资源:照常运行。
需要依赖一个“一致性标记”来实现。
1.3.4 无锁
1.3.5 无等待
无等待:超时无锁
1.4 有关并行的两个重要定律
加速比定义:加速比=优化前系统耗时/优化后系统耗时。
1.4.1 Amdahl 定律
14.2 Gustafson 定律
1.5 回到 Java:JMM
JMM 是围绕着多线程的原子性,可见性,有序性来建立的。
Java 对内存的八种操作:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ALqSdaoe-1627036181895)(C:\Users\cosmoswei\AppData\Roaming\Typora\typora-user-images\image-20210723172619060.png)]
1.5.1 原子性
在32位虚拟机系统来说,long类型的读写不是原子性的(long有64位)。
1.5.2 可见性
1.5.3 有序性
指令重排
1.5.4 那些指令不能重排:Happen-Before 规则
- 程序顺序原则:一个线程内保证语义的串行性。
- volatile 规则:volatile 变量的写,先发生于读,这保证了 volatile 变量的可见性。
- 锁规则:解锁必然发生在加锁前。
- 传递性:A先于B,B先于C,那么A也先于C。
- 线程 start() 方法先于它的每一个动作。
- 线程所有的动作先于线程的终结( Thread.join() )。
- 线程的中断( interrupt() )先于被中断线程的代码。
- 对象的构造函数执行,结束先于 finalize() 方法。
.join() )。
7. 线程的中断( interrupt() )先于被中断线程的代码。
8. 对象的构造函数执行,结束先于 finalize() 方法。