Java线程的生命周期

第一次接触线程的时候,是在操作系统原理这本书籍上看到。第二次接触线程则是在学习Java并发编程的时候。在Java的世界里,多线程是实现并发的主要手段。但是Java语言里的线程本质上就是操作系统的线程,只不过Java对其进行了封装而已。

不管是在操作系统还是Java并发编程,线程都有生命周期。因此,理解线程的主要思路就是搞懂线程生命周期各个节点的状态转换机制。

通用的线程生命周期

通常的线程生命周期通常有五个状态,这五个状态分别是:初始状态、可运行状态、运行状态、休眠状态和终止状态。模型图如下:

这五种状态在不同编程语言里会有简化。例如C语言POSIX和Threads规范,就把初始状态和可运行状态合并;Java语言则把可运行状态和运行状态合并了,这两个状态在操作系统调度层面有用,JVM不关心这两个状态,因为JVM把线程调度交给操作系统处理了。除了简化操作,这五种状态也有可能被细化,比如,Java语言细化了休眠状态。

Java中的线程生命周期

Java语言公有六种状态:

  1. NEW(初始化状态)
  2. RUNNABLE(可运行/运行状态)
  3. BLOCKED(阻塞状态)
  4. WAITING(无时限等待)
  5. TIMED_WAITING(有时限等待)
  6. TERMINATED(终止状态)

因此Java线程的生命周期可以简化为下图:

其中,BLOCKED、WAITING、TIMED_WAITING可以理解为线程导致休眠状态的三种原因。下面分析一下各个状态如何转换。

RUNNABLE与BLOCKED的状态转换

只有一种场景会触发这种转换,就是线程等待synchronized 的隐式锁。synchronized修饰的方法、代码块同一时刻只允许一个线程执行,其他线程只能等待,在这种情况下,等待的线程就会从RUNNABLE转换到BLOCKED状态。而当等待的线程获得synchronized 隐式锁时,就会从BLOCKED 状态转换到 RUNNABLE状态。

RUNNABEL与WAITING的状态转换

有三种场景会触发这种转换

  1. 获得 synchronized 隐式锁的线程调用无参数的 Object.wait()方法
  2. 调用无参数的Thread.join()方法。其中join()是一种线程同步的方法。
  3. 调用LockSupport.park()方法。其中的LockSupport对象,Java并发包中的锁都是基于它实现的。调用LockSupport.park()方法,当前线程会阻塞,线程的状态会从RUNNABEL转换到WAITING状态。调用LockSupport.umpark(Thread thread)课唤醒目标线程,目标线程的状态又会从 WAITING转换到RUNNBALE状态。
RUNNABLE与 TIMED_WAITING的状态转换

有五种场景会触发

  1. 调用带超时参数的 Thread.sleep(long millis) 方法。
  2. 获得 synchronized 隐式锁的线程,调用带超时参数的 Object.wait(long timeout)方法。
  3. 调用带有超时参数的Thread.join(long millis)方法。
  4. 调用带有超时参数的 LockSupport.parkNanos(Object blocker, long deadline)方法。
  5. 调用带有超时参数的 LockSupport.parkUntil(long deadline)方法。
NEW 到 RUNNABLE 的状态转换

调用线程对象的 start()方法就可以了。创建线程对象有两种方法:

  • 继承Thread 对象,重写run()方法
  • 实现 Runnable 接口,重写 run()方法,并将该实现类作为创建 Thread 对象的参数
RUNNABLE 到 TERMINATED 的转换状态

线程执行完 run()方法后,会自动转换到 TERMINATED 状态,如果在线程运行时遇到异常,也会导致线程终止。如果想要强制中断线程,可以调用 interrupt()方法。

参考资料:Java并发编程实战-王宝令

发表评论

电子邮件地址不会被公开。

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部