- 基础
- 并行和并发
- 同步和异步
- 上下文切换
- 死锁(四个必要条件 + 破坏方法)
- 线程活跃性问题(活锁,死锁,饥饿)
1.1 并发和并行
- 并发(concurrent ):同一时间应对多件事的能力。例如:一个人交替做多件事
- 并行(parallel ):同一时间动手做多件事的能力。例如:三个人每人负责一件事
1.2 同步和异步
- 以方法调用为例
- 异步:不需要等待结果返回
- 同步:需要等待结果返回才能继续运行
1.3 上下文切换
- 概念:当前任务在执行完 CPU 时间片切换到另一个任务之前会先保存自己的状态,以便下次再切换回这个任务时,可以再加载这个任务的状态
- 发生条件
- 自己调用了sleep(n), yield(), Object.wait(), join(), park(), synchronized, lock方法
- 有更高级的线程需要运行
- 垃圾回收
- 线程CPU的时间片用完
1.4 死锁
四个必要条件 | 必要条件解释 | 破坏方法 |
互斥条件 | 线程(进程)对于所分配到的资源具有排它性,即一个资源只能被一个线程(进程)占用,直到被该线程(进程)释放 | 这个条件我们没有办法破坏,因为我们用锁本来就是想让他们互斥的(临界资源需要互斥访问) |
请求与保持条件 | 一个线程(进程)因请求被占用资源而发生阻塞时,对已获得的资源保持不放 | 一次性申请所有的资源 |
不剥夺条件 | 线程(进程)已获得的资源在末使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源 | 占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源 |
循环等待条件 | 当发生死锁时,所等待的线程(进程)必定会形成一个环路(类似于死循环),造成永久阻塞 | 靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件 |
1.5 线程活跃性问题
- 活锁:两个线程互相改变对方的结束条件,最后谁也无法结束
static volatile int count = 10;
new Thread(() -> {
while(count > 0){
count--;
}
}).start();
new Thread(() -> {
while(count < 20){
count++;
}
}).start();
- 死锁:一个线程同时需要获取多把锁,容易产生死锁
- 例1:Thread1已经获得了A对象锁,接下来想获得B对象锁;Thread2已经获得了B对象锁,接下来想获得A对象锁 ——> 此时发生死锁
- 例2:哲学家就餐问题
- 饥饿:一个线程由于优先级太低,始终得不到CPU调度执行,无法结束