美文网首页
线程状态及生长周期

线程状态及生长周期

作者: AD刘涛 | 来源:发表于2020-03-12 00:29 被阅读0次

介绍

在本文中,我们将详细讨论Java中的一个核心概念——线程的生命周期。
我们将使用一张图表帮大家理解,当然,还有一些实用的代码片段,以便更好地理解线程执行期间的这些状态。关于如何在Java中创建线程,我们可以参考这片文章开始。

Java中的多线程

在Java语言中,多线程是由线程的核心概念衍生出来的。在其生命周期中,线程会经历各种状态(如图):

线程的6个状态.png

线程中的生命周期

java.lang包中,Thread类包含一个静态枚举,它定义了线程可能存在的状态。在任何给定的时间点上,线程只能处于其中的一种状态:

  1. NEW: 新创建的尚未开始执行的线程
  2. RUNNABLE: 要么在运行,要么就是准备执行,但目前线程正处于资源分配(在等待着CPU为它分配执行时间)。
  3. BLOCKED: 等待获取monitor锁或者尝试访问被其他线程锁住的代码片段时,就会处于该状态
  4. WAITING: 不受时间限制地等待其他线程执行某个特定操作
  5. TIME_WAITING: 等待其他线程在指定的时间内执行特定的操作
  6. TERMINATED: 已完成其执行

所有这些状态都包含在上面的图表中,现在让我们详细讨论其中的每一个。

NEW

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

Blocked

当前线程并不满足运行的条件时,线程就会处于阻塞状态。通常线程在获取锁或者是访问synchronized关键字修饰的方法或代码块(获取锁)时就会进入该状态。

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 enters this
        }
    }
}

以上代码:

  1. 我们创建了2个线程,t1t2.
  2. t1启动并进入synchronized commonResource()方法;这意味着只有一个线程可以访问它;试图访问此方法的其他后续线程将被阻塞,直到当前线程完成该方法的调用。
  3. t1进入该方法时,将会一直处于while循环;这只是模拟繁重的处理,以便所有其他线程都不能进入此方法。
  4. 现在,当我们启动t2时,它试图进入commonResource()方法,然而该方法已经被t1访问,此时t2将处于BLOCKED状态。

Waiting

当线程等待其他线程执行特定操作时,它就处于Waiting状态。根据Java官方文档,任何线程都可以通过调用以下三种方法中的任何一种来进入这种状态:

  • object.wait()
  • thread.join()
  • LockSupport.park()
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());
    }
}

Timed Waiting

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

根据Java官方文档,有五种方法可以将线程置于Timed Waiting状态:

  1. thread.sleep(long millis)
  2. wait(int timeout) or wait(int timeout, int nanos)
  3. thread.join(long millis)
  4. LockSupport.parkNanos
  5. LockSupport.parkUntil

要了解Java中wait()sleep()的更多区别,请阅读这篇专门的文章

现在,让我们试着快速重现这个状态

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,该线程进入5s睡眠状态。

输出结果:

TIMED_WAITING

Terminated

当线程完成执行或异常终止时,线程就会处于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

以上就是线程状态及线程生命周期的讨论。

Waiting 原理(如图)

wait原理.png
  1. 如果有多个线程开始抢锁时,这些线程都会进入entry set集合,等待锁的获取。
  2. 一旦有线程获取锁后再次执行wait方法时,该线程则会对当前锁进行释放,并进入waiting状态。
  3. 直到有线程唤醒,唤醒后的线程再次开始抢锁,直到再次获取到锁。

线程转态转换的特殊情况

  1. object.wait() 状态刚被唤醒时,通常不能立刻抢到monitor锁,那就会从Waiting先进入到Blocked状态,抢到锁后在转换到Runnable状态(官方文档)。
  2. 如果发生异常,可以直接跳到终止Terminated状态,不必再遵循路径,比如可以从Waiting直接跳到Terminated

原文出处

相关文章

  • 线程状态及生长周期

    介绍 在本文中,我们将详细讨论Java中的一个核心概念——线程的生命周期。我们将使用一张图表帮大家理解,当然,还有...

  • 我的涂床

    线程状态及生命周期

  • 线程的学习总结

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

  • Java知识梳理六

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

  • java多线程基本概念(一)

    线程生命周期 说明线程工共包含5个状态: 新建状态new:调用线程构造方法创建线程后,线程进入新建状态; 就绪状态...

  • 线程生命周期及状态分析

    1.线程的状态图 2.sleep、wait、join和park是怎么实现阻塞的? 根据阻塞线程的相关方法分析(包括...

  • Java基础知识(三)

    一、线程状态转化 线程状态生命周期如下: 新建状态(New):新创建了一个线程对象。 就绪状态(Runnable)...

  • 多线程-线程生命周期

    线程总共有6个生命周期状态,线程状态可以通过thread.getState()查看 线程状态是Thread.Sta...

  • 【问答】Java多线程

    线程的状态,画一个线程的生命周期状态图 线程状态:NEW,未启动的线程;RUNNABLE,运行中,包括就绪状态和运...

  • Java 多线程

    关于Java中线程的生命周期,首先看一下下面这张较为经典的图: 线程的生命周期及五种基本状态 上图中基本上囊括了J...

网友评论

      本文标题:线程状态及生长周期

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