《Java高并发程序设计》读书小记
苗锦洲
0
28
198
0
读书小记
友情提示:此篇文章大约需要阅读 6分15秒
# 第1章 走入并行世界
## 1.1 何去何从的并行世界
## 1.2 必须知道的几个概念
### 1.2.1 同步和异步
### 1.2.2 并发和并行
这两个比较容易混淆,都可以表示多个任务一起执行,但侧重点不同。
并发侧重多个任务**交替**执行,并行侧重多个任务**同时**执行。
并发是一定时间内连续执行多个任务,并行是多个任务同时执行。
### 1.2.3 临界区
临界区用来表示公共资源或者说共享数据,可以被多个线程使用,但是每次只能有一个线程使用,其他必须等待使用结束。
### 1.2.4 阻塞和非阻塞
多用来形容多线程间的相互影响。
阻塞:如果占用了临界区的线程不释放资源,其他线程就必须在这个临界区等待。
非阻塞:线程之间不会互相妨碍,所有线程都会不断尝试向前执行。
### 1.2.5 死锁、饥饿和活锁
属于多线程的活跃性问题。
死锁:线程间互相争用资源,导致永远互相等待。
饥饿:一个或多个线程由于种种原因无法获得所需的资源,导致一直无法执行。
活锁:线程所需资源不断在线程之间跳动,导致没有一个线程可以同时拿到所有资源正常执行。
## 1.3 并发级别
### 1.3.1 阻塞
悲观
### 1.3.2 无饥饿
没有优先级,按顺序进入临界区执行
### 1.3.3 无障碍
乐观
先执行,有冲突则回滚
一致性标记:操作完成前后分别读取一致性标记,判断是否更改过,有更改重试,无更改更新标记再修改数据。
### 1.3.4 无锁
无锁和无障碍的不同:无锁的并行总能保证有一个线程可以正常执行,其他线程必须不断重试竞争,可能出现类似饥饿现象。
### 1.3.5 无等待
## 1.4 有关并行的两个重要定律
### 1.4.1 Amdahl定律
### 1.4.2 Gustafson定律
### 1.4.3 二者侧重点不同
A:串行化比例一定,加速比有上限
G:可被并行化比例越大,加速比就可以随着CPU数量线性增长
## 1.5 回到Java:JMM
### 1.5.1 原子性
操作一旦开始,不会被中断
### 1.5.2 可见性
共享变量修改后,其他线程能够立即知道这个修改。
### 1.5.3 有序性
可能发生指令重排,但不会改变串行下的语义
### 1.5.4 Happen-Before规则
判断是否可以重排
# 第2章 Java并行程序基础
## 2.1 有关线程你必须知道的事
- 线程是轻量级的进程,是程序执行的最小单位。
- 线程切换成本比进程切换小。
- Java中线程Thread的所有状态
```java
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
```
- 线程生命周期(注意箭头方向)
```
NEW-(start)->RUNNABLE-(结束)->TERMINATED
RUNNABLE<-(synchronized)->BLOCKED
RUNNABLE-(wait/join)->WAITING
RUNNABLE<-(notify/结束)-WAITING
RUNNABLE-(wait/join)->TIMED_WAITING
RUNNABLE<-(notify/结束)-TIMED_WAITING
```
## 2.2 初始线程:线程的基本操作
### 2.2.1 新建线程
1. 直接 `new Thread()` ,需要重写 `run()` 方法。
2. 或者实现 `Runnable` 接口,在 `new Thread()` 的时候作为参数传进去。
3. *使用线程池*
**注意:不要使用 `run()` 方法开启新线程,这样只会在当前线程串行执行 `run()` 方法中的代码。**
```java
package top.ordinaryroad.learn.chapter._2;
/**
* 线程基本操作
*
* @author mjz
* @date 2021/8/26
*/
public class HelloThread implements Runnable {
public static void main(String[] args) {
Thread t1 = new Thread() {
@Override
public void run() {
System.out.println("Hello Thread t1");
}
};
t1.start();
Thread t2 = new Thread(new HelloThread());
t2.start();
}
@Override
public void run() {
System.out.println("Hello Thread t2");
}
}
```
### 2.2.2 终止线程
**千万不要调用 `stop()` 方法**,这样可能会使数据发生错乱,而且不好排查问题。
可以使用一个布尔类型的变量 `stopMe`
```java
volatile boolean stopMe = false;
```
并提供一个将 `stopMe` 修改为 `true` 的方法
```java
public void stopMe() {
this.stopMe = true;
}
```
在 `run()` 方法体最开始判断这个变量,如果为 `true` 则不执行操作或者跳出循环即可。
### 2.2.3 线程中断
### 2.2.4 等待 `wait` 和通知 `notify`
### 2.2.5 挂起 `suspend` 和继续执行 `resume` 线程
### 2.2.6 等待线程结束 `join` 和谦让 `yeild`
## 2.3 volatile 与 Java 内存模型(JMM)
## 2.4 分门别类的管理:线程组
## 2.5 驻守后台:守护线程(Daemon)
## 2.6 先做重要的事:线程优先级
## 2.7 线程安全的概念与关键字 `synchronized`
## 2.8 程序中的幽灵:隐蔽的错误
### 2.8.1 无提示的错误案例
求平均值整形溢出
### 2.8.2 并发下的ArrayList
### 2.8.3 并发下诡异的HashMap
### 2.8.4 初学者常见问题:错误的加锁
`Integer` 是不变对象,使用 `synchronized(Integer)` 获取到的可能不是同一个对象的锁
评论
楼主暂时不想被别人评论哦~
已自动恢复阅读位置、日/夜间模式参数