Java中线程的生命周期 - Go语言中文社区

Java中线程的生命周期


image

1.简介

在本文中,我们将详细讨论Java中的核心概念 - 线程的生命周期。

我们将使用快速插图的图表,当然还有实用的代码片段,以便在线程执行期间更好地理解这些状态。

要开始理解Java中的Threads,关于创建线程的这篇文章是一个很好的起点。

2. Java中的多线程

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

image.png

3. Java中线程的生命周期

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

1. NEW -新创建的线程尚未启动执行

2. RUNNABLE -运行或准备执行,但它正在等待资源分配

3. BLOCKED -等待获取监视器锁定以进入或重新进入同步块/方法

4. 等待 -等待其他一些线程执行特定操作,没有任何时间限制

5. TIMED_WAITING -等待某个其他线程在指定时间段内执行特定操作

6. TERMINATED -已完成执行

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

3.1 new

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

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


Runnable runnable = new NewState();

Thread t = new Thread(runnable);

Log.info(t.getState());

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


NEW

3.2 Runnable

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

在多线程环境中,Thread-Scheduler(它是JVM的一部分)为每个线程分配固定的时间。因此它会运行一段特定的时间,然后将控件放弃到其他RUNNABLE线程。

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


Runnable runnable = new NewState();

Thread t = new Thread(runnable);

t.start();

Log.info(t.getState());

此代码最有可能返回输出:


RUNNABLE

请注意,在此示例中,并不总是保证在控件到达t.getState()时,它仍将处于RUNNABLE状态。

可能会发生它由Thread-Scheduler立即调度并可能完成执行。在这种情况下,我们可能会得到不同的输出。

3.3 Blocked

当一个线程当前没有资格运行时,它处于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 enters this

        }

    }

}

在这段代码中:

我们创建了两个不同的线程–t1和t2

t1启动并进入同步的commonResource()方法; 这意味着只有一个线程可以访问它; 尝试访问此方法的所有其他后续线程将被阻止进一步执行,直到当前线程完成处理

当t1进入这个方法时,它保持无限循环; 这只是为了模仿繁重的处理,以便所有其他线程都无法进入此方法

现在当我们开始t2时,它尝试输入已经被t1访问的commonResource()方法,因此,t2将保持在BLOCKED状态

处于这种状态,我们调用t2.getState()并获取输出:


BLOCKED

3.4 wait

线程在等待某个其他线程执行特定操作时处于WAITING状态。 根据JavaDocs,任何线程都可以通过调用以下三种方法之一进入此状态:

的Object.wait()

thread.join()或

LockSupport.park()

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

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

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


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处于WAITING状态,直到t2完成执行

由于t1正在等待t2完成,我们从t2调用t1.getState()

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


WAITING

3.5 TIMED_WAITING

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

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

1. thread.sleep(long millis)

2. wait(int timeout)或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,它进入睡眠状态,超时时间为5秒; 输出将是:


TIMED_WAITING

3.6 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

###4 结论

在本教程中,我们了解了Java中线程的生命周期。我们查看了Thread.State枚举定义的所有六个状态,并用快速示例再现它们。

尽管代码片段几乎在每台机器中都会提供相同的输出,但在某些特殊情况下,我们可能会得到一些不同的输出,因为无法确定线程调度程序的确切行为。

而且,与往常一样,此处使用的代码片段可在GitHub上获得。
image

微信关注:JAVA知己,每天更新。

JAVA知己
image

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/feilang00/article/details/86010062
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢