Java多线程基础-线程的状态转换

线程六大状态

根据Thread类中定义的枚举类型State值,可以看出有6中状态:

1
2
3
4
5
6
7
public enum State {
NEW,
RUNNABLE,
WAITING,
TIMED_WAITING,
TERMINATED;
}
  1. 新建状态 NEW

    新建了Thread类对象,但是没有启动的线程。new Thread()

  2. 可运行状态 RUNNABLE

    线程对象新建后,调用start()方法即处于了RUNNABLE状态。

    • 此状态线程可能在Java虚拟机中运行;
    • 可能在等待CPU处理器分配资源。
    • 一个线程只有获取到CPU的资源后,才可以运行其run()方法执行代码,否则就会处于排队等待
  3. 阻塞状态 BLOCKED

    该线程正在等待同步锁来进入一个同步代码块中来使用CPU资源,此时该线程就处于阻塞状态。

  4. 等待状态 WAITING

    线程调用以下方法时,会自己进入等待状态:

    • 不带超时的Object类中的wait()方法
    • 不带超时的Thread类中的join()方法
    • LockSupport类中的park()方法

    一直等待,直到手动唤醒

  5. 超时等待状态 TIMED_WAITING

    线程调用带有正的等待时间参数的下列各方法时,会处于超时等待状态:

    • Object中的wait()
    • Thread中的join()
    • Thread中的sleep()
    • LockSupport中的parkNanos()
    • LockSupport中的parkUntil()
  6. 终止状态 TERMINATED

    • 线程执行完毕,或run()方法全部执行结束后,线程进入终止状态。
    • 终止状态的线程不具备继续运行的能力。

线程状态图

  • 锁池队列:当资源被一个线程访问时,上锁后,其他线程就会进入锁池队列,当锁释放后,其他线程获得了锁,就会变成可运行状态。
  • 《Thinking in Java》中线程被阻塞的五种可能原因:
    1. 线程调用 sleep(ms) ,使线程睡眠,规定时间内,该线程不会运行。
    2. 使用suspend()暂停了线程的执行,除非收到resume()消息,否则不会进入可运行状态
    3. 线程正在等待一些IO操作完成
    4. 线程试图调用另一个对象的同步方法,但那个对象处于锁状态,暂时无法使用
    5. 调用wait()暂停了线程的执行,进入了等待队列。

怎么唤醒一个阻塞的线程

  • 如果线程调用了 wait()、sleep()、join()方法而导致的阻塞,可以中断线程,并抛出InterruptedException来唤醒
  • 如果该线程遇到了IO阻塞,只能等系统IO操作结束后,才能唤醒,Java代码无能为力,无法直接接触到底层操作系统的调度。

怎么检测一个线程是否持有对象监视器

  • Thread类提供了一个holdsLock(Object obj)方法,当且仅当对象obj的监视器被某条线程持有的时候才会返回true
1
public static boolean holdsLock(Object obj)