【JavaSE专栏76】三态和五态,线程的不同状态:新建、运行、状态、阻塞、等待、计时等待状态

简介: 【JavaSE专栏76】三态和五态,线程的不同状态:新建、运行、状态、阻塞、等待、计时等待状态

本文讲解了 Java 中 三态和五态的概念,介绍了新建、运行、状态、阻塞、等待、计时等待状态的应用场景,并给出了样例代码。三态/五态是一种简化的描述,实际中线程可能会在不同的状态之间转换。

一、什么是三态

在 Java 多线程编程中,三态 是指线程的三种状态,包括以下三个状态,请同学们认真学习。

  1. 新建状态:当通过实例化 Thread 类或者创建 Runnable 接口的实现类对象时,线程处于新建状态。此时线程对象被创建,但还没有调用 start() 方法启动线程。
  2. 运行状态:当线程对象调用 start() 方法后,线程进入运行状态。此时线程会执行其 run() 方法中的代码。在运行状态下,线程可能会被操作系统抢占,也可能会主动放弃 CPU 的执行权。
  3. 阻塞状态:当线程正在运行时,可能因为某些原因暂时无法继续执行,进入阻塞状态。常见的阻塞原因包括等待 I/O 操作、等待获取锁等。在阻塞状态下,线程会暂停执行,直到阻塞的原因解除。

此外,还有一个特殊的状态,请同学们注意。

  • 终止状态:当线程的 run() 方法执行完毕或者调用了 Thread 类的 stop() 方法后,线程进入终止状态,终止状态的线程不再具有运行和阻塞的能力,它被称为 死亡

三态是一种简化的描述,实际中线程可能会在不同的状态之间转换。例如,当处于运行状态的线程调用了 sleep() 方法后,会进入阻塞状态;当等待的I/O操作完成后,阻塞的线程会再次进入运行状态。线程状态的转换由操作系统和 Java 运行时环境自动管理,开发人员可以通过调用线程的方法来控制线程的状态转换。


二、什么是五态

在 Java 多线程编程中,五态包括以下 5 55 个状态,请同学们认真学习。

  1. 新建状态:当通过实例化 Thread 类或者创建 Runnable 接口的实现类对象时,线程处于新建状态。此时线程对象被创建,但还没有调用 start() 方法启动线程。
  2. 运行状态:当线程对象调用 start() 方法后,线程进入运行状态。此时线程会执行其 run() 方法中的代码。在运行状态下,线程可能会被操作系统抢占,也可能会主动放弃 CPU 的执行权。
  3. 阻塞状态:当线程正在运行时,可能因为某些原因暂时无法继续执行,进入阻塞状态。常见的阻塞原因包括等待 I/O 操作、等待获取锁等。在阻塞状态下,线程会暂停执行,直到阻塞的原因解除。
  4. 等待状态:线程进入等待状态是因为调用了某些等待方法,如调用了 Object 类的 wait() 方法或者 Thread 类的 join() 方法。在等待状态下,线程会暂停执行,并且释放占用的锁资源,直到被其他线程唤醒。
  5. 计时等待状态:线程进入计时等待状态是因为调用了某些计时等待方法,如调用了 Thread 类的 sleep() 方法或者 Object 类的 wait(long timeout) 方法。与等待状态类似,线程会暂停执行,并且释放占用的锁资源,但是在指定的时间后会自动唤醒。

以上五态是对于普通线程的描述,对于守护线程来说,还有一个特殊的状态:

  • 终止状态:当线程的 run() 方法执行完毕或者调用了 Thread 类的 ·stop()· 方法后,线程进入终止状态,终止状态的线程不再具有运行和阻塞的能力,它被称为 死亡

线程状态的转换由操作系统和 JVM 自动管理,开发人员可以通过调用线程的方法来控制线程的状态转换。


三、五态之间如何转变

在 Java 中,线程的状态是由 JVM 和操作系统自动管理的,开发人员无法直接控制状态的转换

不过,我们可以通过调用线程的不同方法来触发状态的转换,以下是线程状态之间的一些常见转换示例,请同学们认真学习。

  1. 新建状态 -> 运行状态:通过调用线程对象的 start() 方法启动线程,线程会从新建状态转变为运行状态。
  2. 运行状态 -> 阻塞状态:线程可能会因为等待 I/O 操作、等待获取锁或调用了 Thread 类的 sleep() 方法等原因进入阻塞状态。
  3. 运行状态 -> 等待状态:线程调用了 Object 类的 wait() 方法,或者 Thread 类的 join() 方法等待其他线程的完成,进入等待状态。
  4. 运行状态 -> 计时等待状态:线程调用了Thread类的sleep(long millis)方法,或者 **Object** 类的wait(long timeout)` 方法,线程会在指定时间后自动唤醒,进入计时等待状态。
  5. 运行状态 -> 终止状态:线程的 run() 方法执行完毕,或者调用了 Thread 类的 stop() 方法,线程进入终止状态。

线程的状态转换是由 JVM 和操作系统负责管理的,开发人员无法直接控制和预测线程状态的转换。因此,在编写多线程程序时,同学们需要正确处理线程的状态转换,避免潜在的并发问题和死锁情况。

以下是一些 Java 线程五态转换的示例代码,请同学们复制到本地执行。

3.1 新建状态转换到运行状态

Thread thread = new Thread(() -> {
    // 线程执行的任务
});
thread.start(); // 启动线程,线程从新建状态转换为运行状态

3.2 运行状态转换到阻塞状态

public class MyRunnable implements Runnable {
    private Object lock;
    public MyRunnable(Object lock) {
        this.lock = lock;
    }
    @Override
    public void run() {
        synchronized (lock) {
            // 临界区代码
            try {
                Thread.sleep(1000); // 线程休眠,进入阻塞状态
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Main {
    public static void main(String[] args) {
        Object lock = new Object();
        Thread thread1 = new Thread(new MyRunnable(lock));
        Thread thread2 = new Thread(new MyRunnable(lock));
        thread1.start();
        thread2.start();
    }
}

3.3 运行状态转换到等待状态

public class MyRunnable implements Runnable {
    private Object lock;
    public MyRunnable(Object lock) {
        this.lock = lock;
    }
    @Override
    public void run() {
        synchronized (lock) {
            try {
                lock.wait(); // 线程进入等待状态
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Main {
    public static void main(String[] args) {
        Object lock = new Object();
        Thread thread = new Thread(new MyRunnable(lock));
        thread.start();
    }
}

3.4 运行状态转换到计时等待状态

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        try {
            Thread.sleep(2000); // 线程休眠,进入计时等待状态
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Main {
    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.start();
    }
}

3.5 运行状态转换到终止状态

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        // 线程执行的任务
    }
}
public class Main {
    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.start();
        // 等待线程执行完毕,线程从运行状态转换为终止状态
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

以上是一些常见的 Java 线程五态转换的示例代码,通过触发不同的方法或操作来实现状态之间的转换。在实际应用中,同学们需要根据具体的需求和情况灵活使用线程的不同状态来实现并发编程的目标。


四、五态的应用场景

Java 中线程的五态可以在不同的应用场景下发挥作用,以下是一些常见的应用场景,请同学们认真学习。

  1. 新建状态:在创建线程对象后,但还未调用 start() 方法之前的状态。这个状态适用于线程准备工作,例如为线程分配资源、初始化变量等。
  2. 运行状态:线程被启动后进入的状态,线程正在执行 run() 方法中的任务。在并发编程中,可以利用多个运行状态的线程同时执行不同的任务,提高系统的吞吐量和响应性。
  3. 阻塞状态:线程因为某些原因无法执行,进入阻塞状态。这个状态适用于等待外部资源、等待锁或者等待其他线程完成某些操作的情况。例如,当线程需要访问共享资源时,如果该资源已经被其他线程占用,当前线程就会进入阻塞状态,直到资源被释放。
  4. 等待状态:线程调用了 Object 类的 wait() 方法或者 Thread 类的 join() 方法,进入等待状态。这个状态适用于线程间的协调和通信。例如,一个线程等待其他线程完成某些操作后再继续执行。
  5. 计时等待状态:线程调用了 Thread 类的 sleep(long millis) 方法或者 Object 类的 wait(long timeout) 方法,进入计时等待状态。这个状态适用于希望线程暂停一段时间后再继续执行的场景。

这些状态的灵活转换和合理运用,可以实现线程之间的协作、资源的共享和利用,提高程序的并发性能和响应速度。但需要注意的是,对于多线程编程,需要注意线程安全和同步的问题,避免产生不确定的结果和竞态条件。


五、JAVA五态面试题

  1. 请解释Java中线程的五种状态是什么?
  2. 在 Java 中,如何将一个线程从新建状态转变为运行状态?
  3. 什么情况下会使一个线程从运行状态转变为阻塞状态?
  4. 什么是等待状态和计时等待状态?它们之间有何区别?
  5. 如何将一个线程从运行状态转变为等待状态或计时等待状态?
  6. 如何将一个线程从等待状态或计时等待状态转变为运行状态?
  7. 什么情况下会使一个线程从运行状态转变为终止状态?
  8. 在 Java 中,如何正确处理线程的状态转换,以避免潜在的并发问题?


六、总结

本文讲解了 Java 中 三态和五态的概念,介绍了新建、运行、状态、阻塞、等待、计时等待状态的应用场景,并给出了样例代码,在下一篇博客中,将讲解 Java 如何实现线程的创建和启动。


相关文章
|
4月前
|
编解码 网络协议 API
Netty运行原理问题之Netty的主次Reactor多线程模型工作的问题如何解决
Netty运行原理问题之Netty的主次Reactor多线程模型工作的问题如何解决
|
3月前
|
Java Spring
运行@Async注解的方法的线程池
自定义@Async注解线程池
180 3
|
4月前
|
消息中间件 设计模式 安全
多线程魔法:揭秘一个JVM中如何同时运行多个消费者
【8月更文挑战第22天】在Java虚拟机(JVM)中探索多消费者模式,此模式解耦生产与消费过程,提升系统性能。通过`ExecutorService`和`BlockingQueue`构建含2个生产者及4个消费者的系统,实现实时消息处理。多消费者模式虽增强处理能力,但也引入线程安全与资源竞争等挑战,需谨慎设计以确保高效稳定运行。
99 2
【多线程面试题十二】、阻塞线程的方式有哪些?
线程阻塞的方式包括调用sleep()方法、阻塞式IO操作、等待同步监视器的获取、等待通知(notify),以及慎用的suspend()方法。
|
5月前
|
Java C# Python
线程等待(Thread Sleep)
线程等待(Thread Sleep)
|
5月前
|
测试技术
三种等待方式(‌线程等待、‌隐式等待、‌显式等待)
三种等待方式(‌线程等待、‌隐式等待、‌显式等待)
277 4
|
6月前
|
安全 Java
使用notifyAll唤醒所有等待线程
使用notifyAll唤醒所有等待线程
|
5月前
|
安全 开发者
LabVIEW程序退出后线程仍在运行问题
LabVIEW程序退出后线程仍在运行问题
61 2
|
5月前
|
安全 Java
使用notifyAll唤醒所有等待线程
使用notifyAll唤醒所有等待线程
|
6月前
|
前端开发 JavaScript
JavaScript异步处理避免了单线程阻塞,如回调函数、Promise和async/await。
【6月更文挑战第22天】JavaScript异步处理避免了单线程阻塞,如回调函数、Promise和async/await。回调是基础,用于在操作完成后执行函数;Promise管理异步状态,支持链式调用;async/await提供同步代码外观,简化错误处理。每种技术在处理耗时任务时都起着关键作用。
57 3