Java 并发-线程状态
本文介绍 Java 并发编程中的线程状态,如生命周期模型,Java 中的线程状态和转换方式,以及如何中断线程

# Java 并发-线程状态

# 生命周期模型

线程的生命周期即线程在多种状态间转换的过程,可以用五种状态的模型来表示

image-20220120103933424

  1. 初始化状态

    线程在编程语言层面已被创建,而在操作系统层面还未创建真正的线程,如 Java 中还没有调用线程 start 方法

  2. 就绪状态

    操作系统层面的线程已经被创建,等待 CPU 调度执行

  3. 运行状态

    线程获取到 CPU 执行权限,开始执行线程的内容代码

  4. 休眠状态

    线程调用了阻塞式的 API 或者等待某个事件,就会进入休眠状态,释放 CPU 资源

    当等待的事件出现,线程回归就绪状态等待调度

  5. 死亡状态

    线程执行完毕,生命周期结束

# Java 线程状态

  1. Java Thread 内部类 State 中,规定了 Java 线程的几种状态

    public enum State {
        // 初始化状态
        NEW,
        // 就绪 / 运行状态
        RUNNABLE,
        // 阻塞状态
        BLOCKED,
        // 无限等待
        WAITING,
        // 有时限等待
        TIMED_WAITING,
        // 死亡状态
        TERMINATED;
    }
    

    就绪状态和运行状态统一归为 RUNNABLE,而 BLOCKED、WAITING、TIMED_WAITING 都是休眠状态的一种

    需要注意的是调用阻塞式 API,如 IO 阻塞,在操作系统层面表现为休眠状态,但在 Java 虚拟机层面状态是 RUNNABLE

  2. NEW 与 RUNNABLE 的状态转换

    调用 start 方法

    Thread t = new Thread(() -> System.out.println(Thread.currentThread().getState()));
    System.out.println(t.getState());
    t.start();
    // NEW
    // RUNNABLE
    
  3. RUNNABLE 与 BLOCKED 的状态转换

    当执行中的线程等待 synchronized 锁时,状态变为 BLOCKED

    Object o = new Object();
    // 线程 1 获取锁睡 3 秒
    Thread t1 = new Thread(() -> {
        synchronized (o){
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    t1.start();
    Thread t2 = new Thread(() -> {
        synchronized (o){
            System.out.println("t2 run");
        }
    });
    t2.start();
    // 主线程睡 1 秒,用来打印线程 2 没有获取锁的状态
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println(t2.getState()); // BLOCKED
    
  4. RUNNABLE 与 WAITING 的状态转换

    • 获取 synchronized 锁的线程,调用了 wait 方法,notify 后变为 RUNNABLE

    • 线程 A 中调用了线程 B 的 join 方法,线程 A 变为 WAITING 状态,线程 B 执行完毕后线程 A 变为 RUNNABLE

    • LockSupport 的 park 方法是 JDK 并发包中实现锁的基础,会使线程变为 WAITING 状态,调用 unpark 方法后会变为 RUNNABLE

  5. RUNNABLE 与 TIMED_WAITING 的状态转换

    • 转换到 WAITING 的各种方式中,如果使用了超时参数,就是 TIMED_WAITING
    • 调用了带超时参数的 sleep 方法
  6. RUNNABLE 到 TERMINATED 的状态转换

    • run 方法执行完毕或抛出异常

    • 调用了中断线程的方法,如 stop(不推荐使用)

# 中断线程的方式

  1. 使用强制中断的 API

    stop、suspend 方法已经标记为 @Deprecated,不推荐使用

  2. 使用 interrupt 方法通知线程

    当线程内使用了 wait、join、sleep、lockInterruptibly(lock 锁) 这种可以抛出 InterruptedException 异常的 API,调用该线程的 interrupt 方法,就会触发线程内抛出 InterruptedException 异常

    也可以在线程内通过 isInterrupted 方法检查是否被中断,需要注意的是,在捕获异常后中断标记被自动清除,可以使用 Thread.currentThread().interrupt() 重新标记

Comment here, be cool~

Copyright © 2020 CadeCode

Theme 2zh powered by VuePress

本页访问次数 0

Loading