美文网首页
线程生命周期

线程生命周期

作者: Easy的幸福 | 来源:发表于2019-10-16 21:03 被阅读0次
通用的线程生命周期
初始状态、可运行状态、运行状态、休眠状态和终止状态。 image
  • 初始状态

指的是线程已经被创建,但是还不允许分配CPU执行。这个状态属于编程语言特有的,不过这里所谓的被创建,仅仅是在编程语言层面被创建,而在操作系统层面,真正的线程还没有创建。

  • 可运行状态

指的是线程可以分配CPU执行。在这种状态下,真正的操作系统线程已经被成功创建了,所以可以分配CPU执行。

  • 运行状态

当有空闲的CPU时,操作系统会将其分配给一个处于可运行状态的线程,被分配到CPU的线程的状态

  • 休眠状态

休眠状态的线程,会释放CPU使用权,休眠状态的线程永远没有机会获得CPU使用权。

  • 终止状态

线程执行完或者出现异常就会进入终止状态,终止状态的线程不会切换到其他任何状态,进入终止状态也就意味着线程的生命周期结束了。

Java中线程的生命周期

Java语言中线程共有六种状态,分别是:

  • NEW(初始化状态)
  • RUNNABLE(可运行/运行状态)
  • BLOCKED(阻塞状态)
  • WAITING(无时限等待)
  • TIMED_WAITING(有时限等待)
  • TERMINATED(终止状态)

但其实在操作系统层面,Java线程中的BLOCKED、WAITING、TIMED_WAITING是一种状态,即前面我们提到的休眠状态。也就是说只要Java线程处于这三种状态之一,那么这个线程就永远没有CPU的使用权。


image
Java线程中的BLOCKED、WAITING、TIMED_WAITING是一种状态,即前面我们提到的休眠状态。也就是说只要Java线程处于这三种状态之一,那么这个线程就永远没有CPU的使用权。所以Java线程的生命周期可以简化为下图: image
  • RUNNABLE与BLOCKED的状态转换

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

  • RUNNABLE与WAITING的状态转换
    第一种场景,获得synchronized隐式锁的线程,调用无参数的Object.wait()方法。

第二种场景,调用无参数的Thread.join()方法。其中的join()是一种线程同步方法,例如有一个线程对象thread A,当调用A.join()的时候,执行这条语句的线程会等待thread A执行完,而等待中的这个线程,其状态会从RUNNABLE转换到WAITING。当线程thread A执行完,原来等待它的线程又会从WAITING状态转换到RUNNABLE。

第三种场景,调用LockSupport.park()方法。其中的LockSupport对象,也许你有点陌生,其实Java并发包中的锁,都是基于它实现的。调用LockSupport.park()方法,当前线程会阻塞,线程的状态会从RUNNABLE转换到WAITING。调用LockSupport.unpark(Thread thread)可唤醒目标线程,目标线程的状态又会从WAITING状态转换到RUNNABLE。

  • 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状态
1、class MyThread extends Thread
2、class Runner implements Runnable 
  • 从RUNNABLE到TERMINATED状态

线程执行完 run() 方法后,会自动转换到TERMINATED状态,当然如果执行run()方法的时候异常抛出,也会导致线程终止。有时候我们需要强制中断run()方法的执行,例如 run()方法访问一个很慢的网络,我们等不下去了,想终止怎么办呢?Java的Thread类里面倒是有个stop()方法,不过已经标记为@Deprecated,所以不建议使用了。正确的姿势其实是调用interrupt()方法。

那stop()和interrupt()方法的主要区别是什么呢?

不给线程喘息的机会,如果线程持有ReentrantLock锁,被stop()的线程并不会自动调用ReentrantLock的unlock()去释放锁

interrupt()方法仅仅是通知线程,线程有机会执行一些后续操作,同时也可以无视这个通知。被interrupt的线程,是怎么收到通知的呢?一种是异常,另一种是主动检测。

当线程A处于WAITING、TIMED_WAITING状态时,如果其他线程调用线程A的interrupt()方法,会使线程A返回到RUNNABLE状态,同时线程A的代码会触发InterruptedException异常。上面我们提到转换到WAITING、TIMED_WAITING状态的触发条件,都是调用了类似wait()、join()、sleep()这样的方法,我们看这些方法的签名,发现都会throws InterruptedException这个异常。这个异常的触发条件就是:其他线程调用了该线程的interrupt()方法。

当线程A处于RUNNABLE状态时,并且阻塞在java.nio.channels.InterruptibleChannel上时,如果其他线程调用线程A的interrupt()方法,线程A会触发java.nio.channels.ClosedByInterruptException这个异常;而阻塞在java.nio.channels.Selector上时,如果其他线程调用线程A的interrupt()方法,线程A的java.nio.channels.Selector会立即返回。

上面这两种情况属于被中断的线程通过异常的方式获得了通知。还有一种是主动检测,如果线程处于RUNNABLE状态,并且没有阻塞在某个I/O操作上,例如中断计算圆周率的线程A,这时就得依赖线程A主动检测中断状态了。如果其他线程调用线程A的interrupt()方法,那么线程A可以通过isInterrupted()方法,检测是不是自己被中断了。

相关文章

  • 多线程之(线程的生命周期)

    线程的生命周期 如果我们想学会、理解,或者用好线程就必须要知道(熟悉)线程的生命周期。线程的生命周期分为:新建阶段...

  • 线程的学习总结

    我打算从线程得生命周期开始总结多线程: 线程的生命周期: 新建状态:线程对象创建之后,线程进入新建状态. 就绪状态...

  • Thread相关学习之二 - JavaThread&JV

    线程生命周期 JavaThread生命周期 线程生命周期就在上述的6个状态中流转,如下图: JVMTIThread...

  • 需要看的源码

    线程池,看excute的整个过程,线程什么时候会被销毁,线程池的生命周期,线程池里线程的生命周期,项目中怎么用的线...

  • Java知识梳理六

    一、Java多线程一 1.谈谈线程的生命周期和状态转移 关于线程生命周期的不同状态,在Java 5以后,线程...

  • [Java多线程编程之二] 当初叫人家小甜甜,现在叫我牛夫人 —

    一、线程生命周期与状态   一个线程从创建、运行到终止称为一个生命周期,线程在其生命周期中要经历创建、就绪、运行、...

  • 二、【Java并发】线程生命周期以及常用方法

    线程的生命周期 每个线程都有自己的生命周期,下面我们就来详细的了解一下。 从上图我们可以看出线程的生命周期大致可以...

  • 多线程学习笔记

    一.线程基础概念 1.线程生命周期 线程生命周期 新建-就绪-运行-死亡,运行中可以进入阻塞状态 线程执行完任务会...

  • JVM内存区域

    线程私有区域生命周期与线程的生命周期一样,依赖用户线程的启动/结束而创建/销毁(在hotspot vm内,每个线程...

  • 深入Java线程(二)

    为了理解可先看深入Java线程(一)内容在看本篇。 线程生命周期 关于线程生命周期的不同状态,在 Java 5 以...

网友评论

      本文标题:线程生命周期

      本文链接:https://www.haomeiwen.com/subject/wvcpmctx.html