Java中的线程生命周期核心概念

目录
  • Java多线程
  • Java中线程的生命周期
    • NEW
    • Runnable
    • Blocked
    • Waiting
    • Timed Waiting
    • Terminated
  • 结论

前言:

在本文中,我们将详细讨论Java中的一个核心概念——线程的生命周期。我们将使用一个快速的图解,当然还有实用的代码片段来更好地理解线程执行期间的这些状态。

Java多线程

在Java语言中,多线程是由线程的核心概念驱动的。线程在其生命周期中会经历各种状态:

Java中线程的生命周期

java.lang.Thread类包含一个静态枚举,它定义了它的潜在状态。在任何给定的时间点内,线程只能处于以下状态之一:

  • NEW – 一个新创建的线程,尚未开始执行
  • RUNNABLE – 正在运行或准备执行,但它正在等待资源分配
  • BLOCKED – 等待获取监视器锁以进入或重新进入同步块/方法
  • WAITING – 等待其他线程执行特定操作,无任何时间限制
  • TIMED_WAITING – 等待其他线程在指定时间段内执行特定操作
  • TERMINATED – 已完成执行

上图涵盖了所有这些状态;现在让我们详细讨论其中的每一项。

NEW

新线程(或出生线程)是已创建但尚未启动的线程。在我们使用start()方法启动它之前,它一直保持此状态。

以下代码段显示了新创建的处于新状态的线程:

Runnable runnable = new NewState();
Thread t = new Thread(runnable);
Log.info(t.getState());

由于我们尚未启动上述线程,因此方法t.getState()会打印:

NEW

Runnable

当我们创建了一个新线程并对其调用start()方法时,它将从NEW状态移动到RUNNABLE状态。处于此状态的线程正在运行或准备运行,但它们正在等待来自系统的资源分配。

在多线程环境中,线程调度程序(JVM的一部分)为每个线程分配固定的时间量。因此,它会运行一段特定的时间,然后将控制权交给其他可运行的线程。

例如,让我们将t.start()方法添加到前面的代码中,并尝试访问其当前状态:

Runnable runnable = new NewState();
Thread t = new Thread(runnable);
t.start();
Log.info(t.getState());

此代码很可能返回以下输出:

RUNNABLE

请注意:在本例中,并不总是保证在控件到达t.getState()时,它仍处于可运行状态。

线程调度器可能会立即对其进行调度,并可能完成执行。在这种情况下,我们可能会得到不同的输出。

Blocked

当前没有资格运行的线程处于阻塞状态。它在等待监视器锁定并尝试访问被其他线程锁定的代码段时进入此状态。

让我们尝试重现这种状态:

public class BlockedState {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new DemoThreadB());
        Thread t2 = new Thread(new DemoThreadB());
        t1.start();
        t2.start();

        Thread.sleep(1000);

        Log.info(t2.getState());
        System.exit(0);
    }
}
class DemoThreadB implements Runnable {
    @Override
    public void run() {
        commonResource();
    }

    public static synchronized void commonResource() {
        while(true) {
            // Infinite loop to mimic heavy processing
            // 't1' won't leave this method
            // when 't2' try to enter this
        }
    }
}

在此代码中:

  • 我们创建了两个不同的线程—t1t2
  • t1启动并进入synchronized commonResource()方法;这意味着只有一个线程可以访问它;在当前线程完成处理之前,将阻止尝试访问此方法的所有其他后续线程进一步执行
  • t1进入此方法时,它将保持在无限while循环中;这只是为了模拟繁重的处理,以便所有其他线程都无法进入此方法
  • 现在,当我们启动t2时,它尝试进入commonResource()方法,t1已经访问了该方法,因此t2将保持在阻塞状态

处于这种状态,我们称之为t2.getState()并获取输出,如下所示:

BLOCKED

Waiting

线程在等待其他线程执行特定操作时处于等待状态。

根据JavaDocs,任何线程都可以通过调用以下三种方法中的任何一种进入这种状态:

  • object.wait()
  • thread.join()
  • LockSupport.park()

请注意,在wait()join()中,我们没有定义任何超时时间,因为下一节将介绍该场景。

现在,让我们尝试重现这种状态:

public class WaitingState implements Runnable {
    public static Thread t1;

    public static void main(String[] args) {
        t1 = new Thread(new WaitingState());
        t1.start();
    }
    public void run() {
        Thread t2 = new Thread(new DemoThreadWS());
        t2.start();

        try {
            t2.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            Log.error("Thread interrupted", e);
        }
    }
}
class DemoThreadWS implements Runnable {
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            Log.error("Thread interrupted", e);
        }

        Log.info(WaitingState.t1.getState());
    }
}

让我们讨论一下我们在这里做什么:

  • 我们已经创建并启动了t1
  • t1创建t2并启动它
  • t2的处理继续时,我们称之为t2.join(),这会使t1处于等待状态,直到t2完成执行
  • 因为t1正在等待t2完成,所以我们调用t1.getState()来自t2

正如您所期望的那样,这里的输出是:

WAITING

Timed Waiting

当线程等待另一个线程在规定的时间内执行特定操作时,该线程处于TIMED_WAITING状态。

根据JavaDocs,有五种方法可以将线程置于TIMED_WAITING状态:

  • thread.sleep(long millis)
  • wait(int timeout) 或 wait(int timeout, int nanos)
  • thread.join(long millis)
  • LockSupport.parkNanos
  • LockSupport.parkUntil

现在,让我们尝试快速重现这种状态:

public class TimedWaitingState {
    public static void main(String[] args) throws InterruptedException {
        DemoThread obj1 = new DemoThread();
        Thread t1 = new Thread(obj1);
        t1.start();

        // The following sleep will give enough time for ThreadScheduler
        // to start processing of thread t1
        Thread.sleep(1000);
        Log.info(t1.getState());
    }
}
class DemoThread implements Runnable {
    @Override
    public void run() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            Log.error("Thread interrupted", e);
        }
    }
}

这里,我们创建并启动了一个线程t1,该线程进入睡眠状态,超时时间为5秒;

输出将为:

TIMED_WAITING

Terminated

这是死线程的状态。当它完成执行或异常终止时,它处于终止状态。

让我们在以下示例中尝试实现此状态:

public class TerminatedState implements Runnable {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new TerminatedState());
        t1.start();
        // The following sleep method will give enough time for
        // thread t1 to complete
        Thread.sleep(1000);
        Log.info(t1.getState());
    }

    @Override
    public void run() {
        // No processing in this block
    }
}

在这里,虽然我们已经启动了线程t1,但它是下一个语句Thread.sleep(1000)为t1提供了足够的时间来完成,因此该程序为我们提供如下输出:

TERMINATED

除了线程状态之外,我们还可以检查isAlive()方法以确定线程是否处于活动状态。例如,如果我们在此线程上调用isAlive()方法:

Assert.assertFalse(t1.isAlive());

结论

在本文中,我们学习了Java中线程的生命周期。我们查看了线程定义的所有六个状态。陈述enum并用快速示例再现它们。虽然代码片段在几乎每台机器上都会给出相同的输出,但在某些例外情况下,我们可能会得到一些不同的输出,因为无法确定线程调度器的确切行为。

到此这篇关于Java中的线程生命周期核心概念的文章就介绍到这了,更多相关Java线程生命周期内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java线程的生命周期命名与获取代码实现

    一.线程的生命周期 1.五种状态:新建状态.就绪状态.运行状态.阻塞状态.消亡状态 2.就绪状态的线程表示有权利去获取CPU的时间片,CPU时间片是执行权,当线程拿到CPU时间片之后就马上执行run方法,这个时候就代表进入了运行状态 二.线程的调度与控制 通常我们的计算机只有一个CPU,CPU在某一个时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行指令​.在单CPU的机器上线程不是并行运行的,只有个在多个CPU上线程才可以并行运行.Java虚拟机要负责线程的调度,取得CP

  • 深入探究Java线程的状态与生命周期

    目录 一.线程的状态 新建(初始) 就绪(可运行) 运行 阻塞 死亡 二.线程的状态转移 三.线程的生命周期 一.线程的状态 NEW: 安排了工作, 还未开始行动RUNNABLE: 可工作的. 又可以分成正在工作中和即将开始工作.BLOCKED: 这几个都表示排队等着其他事情WAITING: 这几个都表示排队等着其他事情TIMED_WAITING: 这几个都表示排队等着其他事情TERMINATED: 工作完成了 新建(初始) 当继承Thread类和实现了Runnable接口,就可以创建线程,新建

  • Java 线程的生命周期完整实例分析

    本文实例讲述了Java 线程的生命周期.分享给大家供大家参考,具体如下: 一 代码 /** * @Title: ThreadStatus.java * @Description: TODO(演示线程的生命状态) */ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.TimeUnit; public class T

  • Java线程的生命周期和状态控制_动力节点Java学院整理

    一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态(runnable). 注意:不能对已经启动的线程再次调用start()方法,否则会出现Javalang.IllegalThreadStateException异常. 2.就绪状态 处于就绪状态的线程已经具备了运行条件,但还没有分配到CPU,处于线程就绪队列(尽管是采用队列形式,事实上,把它称

  • 一文详解Java线程的6种状态与生命周期

    目录 1.线程状态(生命周期) 2.操作线程状态 2.1.新创建状态(NEW) 2.2.可运行状态(RUNNABLE) 2.3.被阻塞状态(BLOCKED) 2.4.等待唤醒状态(WAITING) 2.5.计时等待状态(TIMED_WAITING) 2.6.终止(TERMINATED) 3.查看线程的6种状态 1.线程状态(生命周期) 一个线程在给定的时间点只能处于一种状态. 线程可以有如下6 种状态: New (新创建):未启动的线程: Runnable (可运行):可运行的线程,需要等待操作

  • 图解Java线程的生命周期

    在Java中,线程有5中不同状态,分别是:新建(New).就绪(Runable).运行(Running).阻塞(Blocked)和死亡(Dead).它们之间的转换图如下: 上图有一个例外,调用yield()方法可以让当前处于运行状态的线程转入就绪状态.如果要测试某线程是否已经死亡,可以使用isAlive()方法,该方法在线程处于就绪.运行.阻塞时放回true,新建和死亡时返回false.不要试图对一个已经死亡的线程调用start()方法而重新启动,死亡就是死亡和人一样,不可能再生.还有也不要对一

  • java 线程的生命周期详解

    一个线程的生命周期: 新建状态: 使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态.它保持这个状态直到程序 start() 这个线程. 就绪状态: 当线程对象调用了start()方法之后,该线程就进入就绪状态.就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度. 运行状态: 如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态.处于运行状态的线程最为复杂,它可以变为阻塞状态.就绪状态和死亡状态. 阻塞状态: 如

  • 初步学习Java中线程的实现与生命周期

    线程的实现 在Java中通过run方法为线程指明要完成的任务,有两种技术来为线程提供run方法: 1.继承Thread类并重写它的run方法.之后创建这个子类的对象并调用start()方法. 2.通过定义实现Runnable接口的类进而实现run方法.这个类的对象在创建Thread的时候作为参数被传入,然后调用start()方法. Thread类是专门用来创建线程和对线程进行操作的类.当某个类继承了Thread类之后,该类就叫做一个线程类. 两种方法均需执行线程的start()方法为线程分配必须

  • Java线程的生命周期的详解

    Java线程的生命周期的详解 对于多线程编程而言,理解线程的生命周期非常重要,本文就针对这一点进行讲解. 一.线程的状态 线程的存在有几种不同的状态,如下: New状态 Ready状态 Running状态 Dead状态 Non Runnable状态 1.New状态 New状态是线程已经被创建,但是还未开始运行的状态.此状态通过调用线程的start()方法可让线程运行. 2.Runnable状态 Runnable状态可称为准备运行状态,也可称为队列,此状态通过调用线程的start()方法可让线程运

  • Java中的线程生命周期核心概念

    目录 Java多线程 Java中线程的生命周期 NEW Runnable Blocked Waiting Timed Waiting Terminated 结论 前言: 在本文中,我们将详细讨论Java中的一个核心概念——线程的生命周期.我们将使用一个快速的图解,当然还有实用的代码片段来更好地理解线程执行期间的这些状态. Java多线程 在Java语言中,多线程是由线程的核心概念驱动的.线程在其生命周期中会经历各种状态: Java中线程的生命周期 java.lang.Thread类包含一个静态枚

  • Java中Servlet的生命周期

    目录 init() service() doGet() doPost() destroy() 方法 架构 Servlet从创建直到毁灭的整个过程: Servlet 初始化后调用 init () 方法 Servlet 调用 service() 方法来处理客户端的请求 Servlet 销毁前调用 destroy() 方法 最后,Servlet 是由 JVM 的垃圾回收器进行GC init() 只调用一次.在第一次创建 Servlet 时被调用,在后续每次用户请求时不再调用.因此,它是用于一次性初始化

  • Java中Servlet的生命周期详解

    目录 Web基础和HTTP协议 什么是Servlet Servlet的生命周期 Web基础和HTTP协议 ┌─────────┐ ┌─────────┐ │░░░░░░░░░│ │O ░░░░░░░│ ├─────────┤ ├─────────┤ │░░░░░░░░░│ │ │ ├─────────┤ │ │ │░░░░░░░░░│ └─────────┘ └─────────┘ │ request 1 │ │─────────────────────>│ │ request 2 │ │───

  • Java线程生命周期及转换过程

    目录 Java 线程生命周期 生命周期转换 1.从 NEW 到 RUNNABLE 2.从 RUNNABLE 到 BLOCKED 3.从 RUNNABLE 到 WAITTING 4.从 RUNNABLE 到 TIMED_WATTING 5.RUNNABLE 到 TERMINATED 总结 前言: 线程的生命周期指的是线程从创建到销毁的整个过程,通常情况下线程的生命周期有以下 5 种: 初始状态 可运行状态 运行状态 休眠状态 终止状态 它们的状态转换如下图所示:  Java 线程生命周期 Java

  • Java线程生命周期的终止与复位

    目录 Thread生命周期 生命周期概述 线程生命周期流程图 线程生命周期测试 启动线程 java中的启动 Hotspot中的启动 线程中断与复位 不要使用stop方法 使用interrupt方法 线程的复位 其他的线程复位 Thread生命周期 生命周期概述 Java的线程状态描述放在Thread类里面的枚举类State中.总共包含了6中状态(从出生到死亡). public enum State { /** * 尚未启动的线程的线程状态 (没有start) */ NEW, /** * 可运行线

  • Java中难理解的四个概念

    前言 Java 是很多人一直在用的编程语言,但是有些 Java 概念是非常难以理解的,哪怕是一些多年的老手,对某些 Java 概念也存在一些混淆和困惑. 所以,在这篇文章里,会介绍四个 Java 中最难理解的四个概念,去帮助开发者更清晰的理解这些概念: 匿名内部类的用法 多线程 如何实现同步 序列化 匿名内部类 匿名内部类又叫匿名类,它有点像局部类(Local Class)或者内部类(Inner Class),只是匿名内部类没有名字,我们可以同时声明并实例化一个匿名内部类. 一个匿名内部类仅适用

  • 详解Spring 中 Bean 的生命周期

    前言 这其实是一道面试题,是我在面试百度的时候被问到的,当时没有答出来(因为自己真的很菜),后来在网上寻找答案,看到也是一头雾水,直到看到了<Spring in action>这本书,书上有对Bean声明周期的大致解释,但是没有代码分析,所以就自己上网寻找资料,一定要把这个Bean生命周期弄明白! ​ 网上大部分都是验证的Bean 在面试问的生命周期,其实查阅JDK还有一个完整的Bean生命周期,这同时也验证了书是具有片面性的,最fresh 的资料还是查阅原始JDK!!! 一.Bean 的完整

  • Java中ThreadLocal线程变量的实现原理

    目录 ThreadLocal是什么? ThreadLocal实现原理分析 ThreadLocal内存泄漏问题 ThreadLocal是什么? ThreadLocal 使得我们可以创建线程私有的变量, 这个变量相对于其他线程来说是不可见的,ThreadLocal为变量在每个线程中都创建了一个副本 , 每个线程可以访问自己私有的线程变量,代码示例如下 : public class ThreadLocalDemo { //创建一个ThreadLocal对象,用来为每个线程会复制保存一份变量,实现线程封

  • 深入讲解Java编程中类的生命周期

    引言         最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前国内java方面的教材大多只是告诉你"怎样做",但至于"为什么这样做"却不多说,所以造成大家在基础和原理方面的知识比较匮乏,所以笔者今天就斗胆来讲一下这个问题,权当抛砖引玉,希望对在这个问题上有疑惑的朋友有所帮助,文中有说的不对的地方,也希望各路高手前来指正.         首先来了

  • 深入理解Asp.Net中WebForm的生命周期

    前言 本文主要给大家介绍的是关于Asp.Net中WebForm生命周期的相关内容,分享出来供大家参考学习,下面来看看详细的介绍: 一.Asp.Net页面生命周期的概念 当我们在浏览器地址栏中输入网址,回车查看页面时,这时会向服务器端IIS)发送一个request请求,服务器就会判断发送过来的请求页面,当完全识别 TTP页面处理程序类后,ASP.NET运行时将调用处理程序的 ProcessRequest 方法来处理请求.创建页面对象.通常情况下,无需更改此方法的实现,因为它是由 Page 类提供的

随机推荐