概述:在多线程编程中,线程个数一般都大于 CPU 个数,而每个 CPU 同一时-刻只能被一个线程使用,为了让用户感觉多个线程是在同时执行的, CPU 资源的分配采用了时间片轮转的策略,也就是给每个线程分配一个时间片,线程在时间片内占用 CPU 执行任务。
定义:当前线程使用完时间片后,就会处于就绪状态并让出 CPU,让其他线程占用,这就是上下文切换,从当前线程的切换到了其他线程。
线程上下文切换时机: 当前线程的 CPU 时间片使用完或者是当前线程被其他线程中断时,当前线程就会释放执行权。那么此时执行权就会被切换给其他的线程进行任务的执行,一个线程释放,另外一个线程获取,就是我们所说的上下文切换时机。
死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的互相等待的现象,在无外力作用的情况下,这些线程会一直相互等待而无法继续运行下去。
- 如上图所示死锁状态,线程 A 己经持有了资源 2,它同时还想申请资源 1,可是此时线程 B 已经持有了资源 1 ,线程 A 只能等待。
- 反观线程 B 持有了资源 1 ,它同时还想申请资源 2,但是资源 2 已经被线程 A 持有,线程 B 只能等待。所以线程 A 和线程 B 就因为相互等待对方已经持有的资源,而进入了死锁状态。
两个线程拥有互斥的资源而且都没有释放。
没有外力强迫其释放,自己也不能主动释放。
场景设计:
结果如下图所示,线程A获取A资源,线程B获取B资源。然后线程A由想要获取B资源,线程B又想获取A资源,他们谁也没有主动释放。
代码讲解:
- package jvm.juc;
-
- public class DeadLock {
- private static Object resoureceA = new Object();
- private static Object resoureceB = new Object();
- public static void main(String[] args) {
- Thread threadA = new Thread(()->{
- System.out.println("线程A-准备获得A资源....");
- synchronized (resoureceA) {
- System.out.println("线程A-已经获得A资源");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("线程A-准备获得B资源");
- synchronized (resoureceB) {
- System.out.println("线程A-已经获得B资源");
- }
- }
- });
- threadA.setName("Thread-A");
- Thread threadB = new Thread(()->{
- System.out.println("线程B-准备获得B资源....");
- synchronized (resoureceB) {
- System.out.println("线程B-已经获得B资源");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("线程B-准备获得A资源");
- synchronized (resoureceA) {
- System.out.println("线程B-已经获得A资源");
- }
- }
- });
- threadA.setName("Thread-B");
-
- threadA.start();
- threadB.start();
-
- }
- }
要想避免死锁,只需要破坏掉至少一个构造死锁的必要条件即可,学过操作系统的读者应该都知道,目前只有请求并持有和环路等待条件是可以被破坏的。
我们,不让他们循环持有相互的资源就行。
- package jvm.juc;
-
- public class DeadLock {
- private static Object resoureceA = new Object();
- private static Object resoureceB = new Object();
- public static void main(String[] args) {
- Thread threadA = new Thread(()->{
- synchronized (resoureceA) {
- System.out.println("线程A-已经获得A资源");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- synchronized (resoureceB) {
- System.out.println("线程A-已经获得B资源");
- }
- }
- });
- threadA.setName("Thread-A");
- Thread threadB = new Thread(()->{
- synchronized (resoureceA) {
- System.out.println("线程B-已经获得A资源");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- synchronized (resoureceB) {
- System.out.println("线程B-已经获得B资源");
- }
- }
- });
- threadA.setName("Thread-B");
-
- threadA.start();
- threadB.start();
-
- }
- }