【多线程:线程六种状态详解】

简介: 【多线程:线程六种状态详解】

【多线程:线程六种状态详解】

01.介绍

我们之前已经介绍过了线程的六种状态,但是介绍的比较浅显,这里我们更加深刻的理解一下线程的六种状态及其代码示例。

02.线程的六种状态

图片解释

NEW 线程刚被创建,但是还没有调用 start() 方法

RUNNABLE 当调用了 start() 方法之后,注意,Java API 层面的 RUNNABLE 状态涵盖了 操作系统 层面的 【可运行状态】、【运行状态】和【阻塞状态】(由于 BIO 导致的线程阻塞,在 Java 里无法区分,仍然认为 是可运行)

BLOCKED , WAITING , TIMED_WAITING 都是 Java API 层面对【阻塞状态】的细分,后面会在状态转换一节 详述 TERMINATED 当线程代码运行结束

这里最应该注意的是RUNNABLE状态 其实是包括了 可运行 运行 阻塞 三个状态,其中阻塞状态是操作系统IO层面的 与 BLOCKED不一样

RUNNABLE 中 阻塞状态 代码

public class TestState2 {
    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            FileReader.read(Constants.FilePath);
        }, "t1").start();

        Thread.sleep(50); // 7行
        System.out.println("ok");
    }
}

结果

我们在第7行打上断点 查看此时t1的状态

可以看出当我们主线程在睡眠50ms期间 t1线程正在读取文件 但还没有读完 此时t1现在属于IO阻塞 但是我们在debug界面可以看到 t1线程现在是RUNNING(就是RUNNABLE debug页面叫做RUNNING)

六种状态示例代码

import lombok.extern.slf4j.Slf4j;
import java.io.IOException;

@Slf4j(topic = "c.TestState")
public class TestState {
    public static void main(String[] args) throws IOException {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                log.debug("running...");
            }
        }; // NEW

        Thread t2 = new Thread("t2") {
            @Override
            public void run() {
                while(true) { // RUNNABLE

                }
            }
        };
        t2.start();

        Thread t3 = new Thread("t3") {
            @Override
            public void run() {
                log.debug("running...");
            }
        };// TERMINATED
        t3.start();

        Thread t4 = new Thread("t4") {
            @Override
            public void run() {
                synchronized (TestState.class) {
                    try {
                        Thread.sleep(1000000); // TIMED_WAITING
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        t4.start();

        Thread t5 = new Thread("t5") {
            @Override
            public void run() {
                try {
                    t2.join(); // WAITING
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        t5.start();

        Thread t6 = new Thread("t6") {
            @Override
            public void run() {
                synchronized (TestState.class) { // BLOCKED
                    try {
                        Thread.sleep(1000000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        t6.start();

        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.debug("t1 state {}", t1.getState());
        log.debug("t2 state {}", t2.getState());
        log.debug("t3 state {}", t3.getState());
        log.debug("t4 state {}", t4.getState());
        log.debug("t5 state {}", t5.getState());
        log.debug("t6 state {}", t6.getState());
        System.in.read();
    }
}

结果

16:36:39.975 c.TestState [t3] - running...
16:36:40.474 c.TestState [main] - t1 state NEW
16:36:40.475 c.TestState [main] - t2 state RUNNABLE
16:36:40.475 c.TestState [main] - t3 state TERMINATED
16:36:40.476 c.TestState [main] - t4 state TIMED_WAITING
16:36:40.476 c.TestState [main] - t5 state WAITING
16:36:40.476 c.TestState [main] - t6 state BLOCKED

解释

我们一个一个来分析

t1:我们创建了一个线程对象t1 但没有进行start所以状态为NEW

t2:t2线程的run方法里是一个永真循环 一直占用cpu 所以是RUNNABLE状态

t3:t3线程run方法里就只有一个输出语句 当运行完后 此线程终结 所以状态为 TERMINATED

t4:t4线程run方法里有一个sleep方法 线程睡眠期间属于TIMED_WAITING状态 期间不参与cpu调度 睡眠结束后变为就绪态(RUNNABLE中的可运行状态)

t5:t5线程run方法里有一个t2线程的join方法 t2线程同步到t5线程 同步期间 t5线程为 WAITING状态 期间不参与cpu调度 t2线程结束后 t5线程变为就绪态(RUNNABLE中的可运行状态)

t6:t6线程与t4线程都被加锁 其监听器都为 TestState.class,又因为此时t4线程先被锁定,t6线程此时没有抢到锁 所以此时t6线程为BLOCKED状态 此状态不参与cpu调度 获得锁后转变为就绪态 注意与 RUNNABLE里的阻塞不是一个东西 RUNNABLE阻塞指的是IO层面的阻塞,BLOCKED指的是java层面的阻塞

目录
相关文章
|
1月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
41 1
C++ 多线程之初识多线程
|
22天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
16 3
|
22天前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
15 2
|
22天前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
28 2
|
22天前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
28 1
|
22天前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
33 1
|
22天前
|
Java
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件成立时被唤醒,从而有效解决数据一致性和同步问题。本文通过对比其他通信机制,展示了 `wait()` 和 `notify()` 的优势,并通过生产者-消费者模型的示例代码,详细说明了其使用方法和重要性。
24 1
|
1月前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
45 6
|
1月前
|
存储 运维 NoSQL
Redis为什么最开始被设计成单线程而不是多线程
总之,Redis采用单线程设计是基于对系统特性的深刻洞察和权衡的结果。这种设计不仅保持了Redis的高性能,还确保了其代码的简洁性、可维护性以及部署的便捷性,使之成为众多应用场景下的首选数据存储解决方案。
40 1
|
1月前
|
C++
C++ 多线程之线程管理函数
这篇文章介绍了C++中多线程编程的几个关键函数,包括获取线程ID的`get_id()`,延时函数`sleep_for()`,线程让步函数`yield()`,以及阻塞线程直到指定时间的`sleep_until()`。
23 0
C++ 多线程之线程管理函数