线程生命周期

现代操作系统在运行一个程序时,会为其创建一个进程。例如,启动一个Java程序,操作系统就会创建一个Java进程。现代操作系统调度的最小单元是线程,也叫轻量级进程(Light Weight Process),在一个进程里可以创建多个线程,这些线程都拥有各自的计数器、堆栈和局部变量等属性,并且能够访问共享的内存变量。处理器在这些线程上高速切换,让使用者感觉到这些线程在同时执行。

CPU再切换线程是会导致线程存在各种状态,线程从创建到死亡其中存在不同的生命状态;本文将对线程生命周期进行全面的介绍。

Java线程的状态可以从java.lang.Thread的内部枚举类java.lang.Thread$State得知:

public enum State {

    NEW,

    RUNNABLE,

    BLOCKED,

    WAITING,

    TIMED_WAITING,

    TERMINATED;
}

当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中,它要经过 新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked、WATING、TIMED_WATING)和死亡(Dead)5种状态。尤其是当线程启动以后,它不可能一直"霸占"着CPU独自运行,所以CPU需要在多条线程之间切换,于是 线程状态也会多次在运行、阻塞之间切换

  • 新建状态(New)

    API注释

    /**
    * Thread state for a thread which has not yet started.
    * 线程实例尚未启动时候的线程状态
    */
    NEW,

    当线程对象创建后,即进入新建状态,如:Thread t = new MyThread();

  • 就绪状态(Runnable)

    API注释

    /**
    * Thread state for a runnable thread. A thread in the runnable
    * state is executing in the Java virtual machine but it may
    * be waiting for other resources from the operating system
    * such as processor.
    */
    RUNNABLE, 可运行状态下线程的线程状态。可运行状态下的线程在Java虚拟机中执行,但它可能执行等待操作系统的其他资源,例如处理器。

    当调用线程对象的start()方法时,线程即进入就绪状态。处于就绪状态的线程只是说明此线程已经做好准备,随时等待CPU调度执行,并不是说执行了start()方法就立即执行。

    当Java线程实例调用了Thread#start()之后,就会进入RUNNABLE状态。RUNNABLE状态可以认为包含两个子状态:READYRUNNING

    • READY:该状态的线程可以被线程调度器进行调度使之更变为RUNNING状态。
    • RUNNING:该状态表示线程正在运行,线程对象的run()方法中的代码所对应的的指令正在被CPU执行。
    • 当Java线程实例Thread#yield()方法被调用时或者由于线程调度器的调度,线程实例的状态有可能由RUNNING转变为READY,但是从线程状态Thread#getState()获取到的状态依然是RUNNABLE。例如:
    • public class ThreadState1 {
      
          public static void main(String[] args) throws Exception {
      Thread thread = new Thread(()-> {
      while (true){
      Thread.yield();
      }
      });
      thread.start();
      Thread.sleep(2000);
      System.out.println(thread.getState());
      }
      }
      // 输出结果
      RUNNABLE
  • 运行状态(Running)

    当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。

  • WATING状态

WAITING无限期的等待状态,这种状态下的线程不会被分配CPU执行时间。当一个线程执行了某些方法之后就会进入无限期等待状态,直到被显式唤醒,被唤醒后,线程状态由WAITING更变为RUNNABLE然后继续执行。

  • TIMED WATING状态

TIMED WAITING就是有限期等待状态,它和WAITING有点相似,这种状态下的线程不会被分配CPU执行时间,不过这种状态下的线程不需要被显式唤醒,只需要等待超时限期到达就会被VM唤醒,有点类似于现实生活中的闹钟。

  • 阻塞状态(Blocked)

处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。

阻塞状态分类

  1. 等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
  2. 同步阻塞:线程在获取synchronized同步锁失败(因为锁被其它线程占用),它会进入到同步阻塞状态;
  3. 其他阻塞:通过调用线程的sleep()或join()或发出I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
  • 死亡状态

    线程执行完毕或者是异常退出,该线程结束生命周期。

线程相关方法

public class Thread{
// 线程的启动
public void start();
// 线程体
public void run();
// 已废弃
public void stop();
// 已废弃
public void resume();
// 已废弃
public void suspend();
// 在指定的毫秒数内让当前正在执行的线程休眠
public static void sleep(long millis);
// 同上,增加了纳秒参数
public static void sleep(long millis, int nanos);
// 测试线程是否处于活动状态
public boolean isAlive();
// 中断线程 - 进入阻塞状态
public void interrupt();
// 测试线程是否已经中断
public boolean isInterrupted();
// 测试当前线程是否已经中断
public static boolean interrupted();
// 等待该线程终止
public void join() throws InterruptedException;
// 等待该线程终止的时间最长为 millis 毫秒
public void join(long millis) throws InterruptedException;
// 等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒
public void join(long millis, int nanos) throws InterruptedException;
}

笔者的微信公众号,每天一篇好文章:

java并发编程-线程生命周期的更多相关文章

  1. java并发编程基础—生命周期与线程控制

    一.线程生命周期 线程被创建启动以后,他既不是一启动就进入执行状态,也不是一直处于执行状态,在线程的生命周期中,它要经过新建(New).就绪(Runnable).运行(Running).阻塞(Bloc ...

  2. Java 并发编程 | 线程池详解

    原文: https://chenmingyu.top/concurrent-threadpool/ 线程池 线程池用来处理异步任务或者并发执行的任务 优点: 重复利用已创建的线程,减少创建和销毁线程造 ...

  3. java并发编程 线程基础

    java并发编程 线程基础 1. java中的多线程 java是天生多线程的,可以通过启动一个main方法,查看main方法启动的同时有多少线程同时启动 public class OnlyMain { ...

  4. java并发编程 | 线程详解

    个人网站:https://chenmingyu.top/concurrent-thread/ 进程与线程 进程:操作系统在运行一个程序的时候就会为其创建一个进程(比如一个java程序),进程是资源分配 ...

  5. Java并发编程:线程间通信wait、notify

    Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...

  6. Java并发编程:线程和进程的创建(转)

    Java并发编程:如何创建线程? 在前面一篇文章中已经讲述了在进程和线程的由来,今天就来讲一下在Java中如何创建线程,让线程去执行一个子任务.下面先讲述一下Java中的应用程序和进程相关的概念知识, ...

  7. Java并发编程——线程的基本概念和创建

    一.线程的基本概念: 1.什么是进程.什么是是线程.多线程? 进程:一个正在运行的程序(程序进入内存运行就变成了一个进程).比如QQ程序就是一个进程. 线程:线程是进程中的一个执行单元,负责当前进程中 ...

  8. Java并发编程——线程池的使用

    在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统 ...

  9. Java并发编程——线程池

    本文的目录大纲: 一.Java中的ThreadPoolExecutor类 二.深入剖析线程池实现原理 三.使用示例 四.如何合理配置线程池的大小 一.Java中的ThreadPoolExecutor类 ...

随机推荐

  1. [工具-002]把png图片转换成ico图标

    最近我收到了上级的一个需求,我们需要使用产品的png图片,批量转换成ico图片,然后调用上一篇的方法,替换可执行程序的图标.一开始查看资料的时候,C#有直接可以转成ico图片的方法,很简单.但是生成的 ...

  2. raw_input和input

    昨天在OJ上做CTF的题目,发现有道python的题目很有意思,让我知道了raw_input和input的区别,并且能干一些别的事情. 官方文档上说,input()相当于eval(raw_input( ...

  3. 05 . 前端之BootStrap

    BootStrap简介 Bootstrap是美国Twitter公司的设计师Mark Otto和Jacob Thornton合作基于HTML.CSS.JavaScript 开发的简洁.直观.强悍的前端开 ...

  4. itext7史上最全实战总结

    1. itext7史上最全实战总结 1.1. 前言 最近有个需求需要我用Java手动写一份PDF报告,经过考察几种pdf开源代码,最终选取了itext7,此版本为7.1.11,由于发现网上关于该工具的 ...

  5. 高性能可扩展mysql 笔记(三)Hash分区、RANGE分区、LIST分区

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.MySQL分区表操作 1.定义:数据库表分区是数据库基本设计规范之一,分区表在物理上表现为多个文件, ...

  6. Java实现 LeetCode 814 二叉树剪枝 (遍历树)

    814. 二叉树剪枝 给定二叉树根结点 root ,此外树的每个结点的值要么是 0,要么是 1. 返回移除了所有不包含 1 的子树的原二叉树. ( 节点 X 的子树为 X 本身,以及所有 X 的后代. ...

  7. Java实现 蓝桥杯VIP 算法训练 数的划分

    [题目描述] 将整数n分成k份,且每份不能为空,任意两份不能相同(不考虑顺序). 例如:n=7,k=3,下面三种分法被认为是相同的. 1,1,5: 1,5,1: 5,1,1: 问有多少种不同的分法. ...

  8. java中Condition类的详细介绍(详解)

    已找不到原文了,还望原文博主看到能告诉小白一下,一定标注原文地址 一 condition 介绍及demo Condition是在java 1.5中才出现的,它用来替代传统的Object的wait(). ...

  9. Java实现第八届蓝桥杯外星日历

    外星日历 题目描述 某星系深处发现了文明遗迹. 他们的计数也是用十进制. 他们的文明也有日历.日历只有天数,没有年.月的概念. 有趣的是,他们也使用了类似"星期"的概念, 只不过他 ...

  10. Linux文本编辑vi基本操作

    vi是Linux/Unix最常用的全屏幕文本编辑器,他的作用是显示.编辑.建立文本文件.它没有菜单,只有命令. vi工作模式图: 编辑模式进入插入模式命令:A:在光标所在行尾插入 a:在光标所在字符后 ...