OR博客
《Java高并发程序设计》读书小记
苗锦洲
创建于:2021-08-23 22:44:34
0
28
198
0
读书小记
# 第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)` 获取到的可能不是同一个对象的锁
评论
楼主暂时不想被别人评论哦~