Life Cycle of a Thread in Java – Java中线程的生命周期

最后修改: 2018年 2月 17日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

In this article, we’ll discuss in detail a core concept in Java – the lifecycle of a thread.

在这篇文章中,我们将详细讨论Java中的一个核心概念–线程的生命周期。

We’ll use a quick illustrated diagram and, of course, practical code snippets to better understand these states during the thread execution.

我们将使用一个快速的图示,当然还有实用的代码片段来更好地理解线程执行过程中的这些状态。

To get started understanding Threads in Java, this article on creating a thread is a good place to start.

要开始了解Java中的线程,这篇关于创建线程的文章是一个不错的开始。

2. Multithreading in Java

2.Java中的多线程

In the Java language, multithreading is driven by the core concept of a Thread. During their lifecycle, threads go through various states:

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

Life Cycle of a Thread

3. Life Cycle of a Thread in Java

3.Java中线程的生命周期

The java.lang.Thread class contains a static State enum – which defines its potential states. During any given point of time, the thread can only be in one of these states:

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

  1. NEW – a newly created thread that has not yet started the execution
  2. RUNNABLE – either running or ready for execution but it’s waiting for resource allocation
  3. BLOCKED – waiting to acquire a monitor lock to enter or re-enter a synchronized block/method
  4. WAITING – waiting for some other thread to perform a particular action without any time limit
  5. TIMED_WAITING – waiting for some other thread to perform a specific action for a specified period
  6. TERMINATED – has completed its execution

All these states are covered in the diagram above; let’s now discuss each of these in detail.

所有这些状态都涵盖在上图中;现在我们来详细讨论每一种状态。

3.1. New

3.1.新的

A NEW Thread (or a Born Thread) is a thread that’s been created but not yet started. It remains in this state until we start it using the start() method.

一个NEW Thread(或一个Born Thread)是一个已经创建但尚未启动的线程。它一直处于这种状态,直到我们使用start() 方法启动它。

The following code snippet shows a newly created thread that’s in the NEW state:

下面的代码片断显示了一个新创建的线程,它处于NEW状态。

Runnable runnable = new NewState();
Thread t = new Thread(runnable);
System.out.println(t.getState());

Since we’ve not started the mentioned thread, the method t.getState() prints:

由于我们还没有启动提到的线程,方法t.getState()打印。

NEW

3.2. Runnable

3.2.可运行

When we’ve created a new thread and called the start() method on that, it’s moved from NEW to RUNNABLE state. Threads in this state are either running or ready to run, but they’re waiting for resource allocation from the system.

当我们创建了一个新的线程并对其调用start()方法时,它就从NEW状态转移到RUNNABLE状态。该状态下的线程要么正在运行,要么准备运行,但它们正在等待系统的资源分配。

In a multi-threaded environment, the Thread-Scheduler (which is part of JVM) allocates a fixed amount of time to each thread. So it runs for a particular amount of time, then relinquishes the control to other RUNNABLE threads.

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

For example, let’s add t.start() method to our previous code and try to access its current state:

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

Runnable runnable = new NewState();
Thread t = new Thread(runnable);
t.start();
System.out.println(t.getState());

This code is most likely to return the output as:

这段代码最可能返回的输出为。

RUNNABLE

Note that in this example, it’s not always guaranteed that by the time our control reaches t.getState(), it will be still in the RUNNABLE state.

注意,在这个例子中,并不能保证当我们的控件到达t.getState()时,它仍然处于RUNNABLE状态。

It may happen that it was immediately scheduled by the Thread-Scheduler and may finish execution. In such cases, we may get a different output.

可能发生的情况是,它被Thread-Scheduler立即安排,并可能完成执行。在这种情况下,我们可能会得到一个不同的输出。

3.3. Blocked

3.3.被封杀

A thread is in the BLOCKED state when it’s currently not eligible to run. It enters this state when it is waiting for a monitor lock and is trying to access a section of code that is locked by some other thread.

当一个线程目前没有资格运行时,它就处于BLOCKED状态。当它在等待一个监视器锁,并试图访问被其他线程锁定的一段代码时,它就会进入这种状态。

Let’s try to reproduce this state:

让我们试着重现这种状态。

public class BlockedState {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new DemoBlockedRunnable());
        Thread t2 = new Thread(new DemoBlockedRunnable());
        
        t1.start();
        t2.start();
        
        Thread.sleep(1000);
        
        System.out.println(t2.getState());
        System.exit(0);
    }
}

class DemoBlockedRunnable 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
        }
    }
}

In this code:

在这个代码中。

  1. We’ve created two different threads – t1 and t2
  2. t1 starts and enters the synchronized commonResource() method; this means that only one thread can access it; all other subsequent threads that try to access this method will be blocked from the further execution until the current one will finish the processing
  3. When t1 enters this method, it is kept in an infinite while loop; this is just to imitate heavy processing so that all other threads cannot enter this method
  4. Now when we start t2, it tries to enter the commonResource() method, which is already being accessed by t1, thus, t2 will be kept in the BLOCKED state

Being in this state, we call t2.getState() and get the output as:

在这种状态下,我们调用t2.getState(),得到的输出为。

BLOCKED

3.4. Waiting

3.4.等待

A thread is in WAITING state when it’s waiting for some other thread to perform a particular action. According to JavaDocs, any thread can enter this state by calling any one of the following three methods:

当一个线程在等待其他线程执行某个特定的动作时,它处于WAITING状态。 根据JavaDocs,任何线程都可以通过调用以下三个方法中的任何一个进入这个状态。

  1. object.wait()
  2. thread.join() or
  3. LockSupport.park()

Note that in wait() and join() – we do not define any timeout period as that scenario is covered in the next section.

请注意,在wait()join()中,我们没有定义任何超时时间,因为这种情况将在下一节中涉及。

We have a separate tutorial that discusses in detail the use of wait(), notify() and notifyAll().

我们有单独的教程,详细讨论了wait()notify()notifyAll()的使用。

For now, let’s try to reproduce this state:

现在,让我们试着重现这种状态。

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 DemoWaitingStateRunnable());
        t2.start();

        try {
            t2.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            e.printStackTrace();
        }
    }
}

class DemoWaitingStateRunnable implements Runnable {
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            e.printStackTrace();
        }
        
        System.out.println(WaitingState.t1.getState());
    }
}

Let’s discuss what we’re doing here:

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

  1. We’ve created and started the t1
  2. t1 creates a t2 and starts it
  3. While the processing of t2 continues, we call t2.join(), this puts t1 in WAITING state until t2 has finished execution
  4. Since t1 is waiting for t2 to complete, we’re calling t1.getState() from t2

The output here is, as you’d expect:

这里的输出是,正如你所期望的那样。

WAITING

3.5. Timed Waiting

3.5.定时等待

A thread is in TIMED_WAITING state when it’s waiting for another thread to perform a particular action within a stipulated amount of time.

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

According to JavaDocs, there are five ways to put a thread on TIMED_WAITING state:

根据JavaDocs,有五种方法可以将线程置于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

To read more about the differences between wait() and sleep() in Java, have a look at this dedicated article here.

要阅读更多关于Java中wait()sleep()之间的差异,请看这里的专门文章

For now, let’s try to quickly reproduce this state:

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

public class TimedWaitingState {
    public static void main(String[] args) throws InterruptedException {
        DemoTimeWaitingRunnable runnable= new DemoTimeWaitingRunnable();
        Thread t1 = new Thread(runnable);
        t1.start();
        
        // The following sleep will give enough time for ThreadScheduler
        // to start processing of thread t1
        Thread.sleep(1000);
        System.out.println(t1.getState());
    }
}

class DemoTimeWaitingRunnable implements Runnable {
    @Override
    public void run() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            e.printStackTrace();
        }
    }
}

Here, we’ve created and started a thread t1 which is entered into the sleep state with a timeout period of 5 seconds; the output will be:

在这里,我们创建并启动了一个线程t1,它进入了睡眠状态,超时时间为5秒;输出结果将是。

TIMED_WAITING

3.6. Terminated

3.6.终止

This is the state of a dead thread. It’s in the TERMINATED state when it has either finished execution or was terminated abnormally.

这是一个死线程的状态。当它已经完成执行或被异常终止时,它就处于TERMINATED状态。

We have a dedicated article that discusses different ways of stopping the thread.

我们有一篇专门的文章,讨论了停止线程的不同方法。

Let’s try to achieve this state in the following example:

让我们在下面的例子中尝试实现这种状态。

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);
        System.out.println(t1.getState());
    }
    
    @Override
    public void run() {
        // No processing in this block
    }
}

Here, while we’ve started thread t1, the very next statement Thread.sleep(1000) gives enough time for t1 to complete and so this program gives us the output as:

在这里,虽然我们已经启动了线程t1,但接下来的语句Thread.sleep(1000)给了t1足够的时间来完成,所以这个程序给我们的输出为。

TERMINATED

In addition to the thread state, we can check the isAlive() method to determine if the thread is alive or not. For instance, if we call the isAlive() method on this thread:

除了线程状态,我们还可以检查isAlive()方法来确定线程是否活着。例如,如果我们在这个线程上调用isAlive()方法。

Assert.assertFalse(t1.isAlive());

It returns false. Put simply, a thread is alive if and only if it has been started and has not yet died.

它返回false。简单地说,一个线程是活的,当且仅当它已被启动且尚未死亡。

4. Conclusion

4.结论

In this tutorial, we learned about the life-cycle of a thread in Java. We looked at all six states defined by Thread.State enum and reproduced them with quick examples.

在本教程中,我们了解了Java中线程的生命周期。我们研究了Thread.State枚举所定义的所有六种状态,并通过快速的例子再现了这些状态。

Although the code snippets will give the same output in almost every machine, in some exceptional cases, we may get some different outputs as the exact behavior of Thread Scheduler cannot be determined.

虽然这些代码片段在几乎每台机器上都会有相同的输出,但在一些特殊情况下,我们可能会得到一些不同的输出,因为线程调度器的确切行为无法确定。

And, as always, the code snippets used here are available on GitHub.

而且,像往常一样,这里使用的代码片段都是在GitHub上提供的