• 基础
  • 并行和并发
  • 同步和异步
  • 上下文切换
  • 死锁(四个必要条件 + 破坏方法)
  • 线程活跃性问题(活锁,死锁,饥饿)

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调度执行,无法结束