【JAVA多线程】线程的状态控制

news2024/9/20 5:22:19

目录

1.JDK中的线程状态

2.基础操作

2.1关闭

2.2中断

2.3.等待、唤醒

2.4.阻塞、唤醒


1.JDK中的线程状态

在JDK的线程体系中线程一共6种状态:

  • NEW(新建): 当线程对象创建后,但尚未启动时,线程处于新建状态。
  • RUNNABLE(可运行): 当线程调用start()方法后,线程将变为可运行状态。此时线程可能正在运行,也可能正在等待CPU分配时间片。
  • BLOCKED(阻塞): 这个状态通常指线程在等待锁。当多个线程试图同时访问同步块或方法时,没有获得锁的线程将被阻塞。
  • WAITING(等待): 线程进入等待状态是因为调用了Object.wait(), Thread.join(), 或LockSupport.park()等方法。等待状态的线程不会竞争锁,也不会消耗CPU时间。
  • TIMED_WAITING(定时等待): 类似于等待状态,但线程将在一定时间后自动恢复到可运行状态,例如调用Thread.sleep(long millis)或wait(long timeout)。
  • TERMINATED(终止): 线程执行完毕或因异常而终止,将进入终止状态。

线程状态之间的转换如下:

  • NEW -> RUNNABLE: 调用线程的start()方法后发生。
  • RUNNABLE -> BLOCKED: 当线程尝试获取一个已被其他线程持有的锁时发生。
  • RUNNABLE -> WAITING/TIMED_WAITING: 当线程调用等待方法时发生。
  • BLOCKED -> RUNNABLE: 当线程获得了锁,或者锁被释放时发生。
  • WAITING/TIMED_WAITING -> RUNNABLE: 当等待条件满足,如其他线程调用了notify()或notifyAll(),或者定时等待时间到期时发生。
  • RUNNABLE -> TERMINATED: 当线程的run()方法完成或抛出未捕获的异常时发生。

其中需要值得重点关注的是等待(wait、timed_waiting)和阻塞(blocked):

  • 等待,线程不往下执行,不让出cpu资源

  • 阻塞,线程不往下执行,让出cpu资源。

其实在操作系统中线程一共就三大类状态,运行、阻塞、就绪,JDK中的等待和阻塞都归为阻塞这一大类状态中,等待又叫轻量级阻塞,阻塞又叫重量级阻塞。当在JDK的多线程体系里有大量的地方会用到等待/唤醒、阻塞/唤醒的两套api:

  • wait()阻塞线程、notify()唤醒线程

  • usfe.park()阻塞线程、usfe.unpark()唤醒线程

2.基础操作

2.1关闭

JAVA提供stop()、destory()两个函数来强制杀死线程,但是这两个方法已经被废弃,因为它们可能导致数据不一致和其他严重的副作用,比如资源泄漏。Thread.stop()方法会立即停止线程,并且会抛出ThreadDeath错误,这可能会导致线程在未清理资源的情况下突然终止。

推荐使用以下两种方式进行线程的关闭:

  • 守护线程,守护线程是一种特殊的线程类型,它不会阻止JVM的关闭。当JVM中不再有非守护线程运行时,JVM会自动退出,即使还有守护线程在运行。

  • 标志位,使用标志位是一种常见的线程终止策略,线程会在每次循环中检查标志位的状态,如果标志位被设置为true,则线程会退出循环并终止。

守护线程代码示例:

public class DaemonThreadExample {

    public static void main(String[] args) throws InterruptedException {
        Thread daemonThread = new Thread(() -> {
            while (true) {
                System.out.println("Daemon thread running...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    System.out.println("Daemon thread interrupted.");
                    break;
                }
            }
        });
        daemonThread.setDaemon(true); // 设置为守护线程
        daemonThread.start();

        // 主线程休眠一段时间后退出,此时守护线程也会随之退出
        Thread.sleep(5000);
    }
}

标志位代码示例:

public class FlagBasedTermination {

    private volatile boolean stopRequested = false;

    public void requestStop() {
        this.stopRequested = true;
    }

    public void runTask() {
        while (!stopRequested) {
            // 执行任务...
            System.out.println("Task running...");

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                System.out.println("Task interrupted.");
                break;
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        FlagBasedTermination task = new FlagBasedTermination();
        Thread taskThread = new Thread(task::runTask);
        taskThread.start();

        // 主线程休眠一段时间后请求停止子线程
        Thread.sleep(5000);
        task.requestStop();
    }
}

2.2中断

中断,不是指中断线程,而是指中断阻塞,唤醒线程。只有轻量级阻塞能够被中断,重量级阻塞不能被中断。

  • 轻量级阻塞,即等待状态,对应的JAVA线程中的状态有:

    • WAITING

    • TIMED_WAITING

  • 重量级阻塞,即阻塞状态,对应的JAVA线程中的状态有:

    • BLOCKED

JAVA提供了两个与中断阻塞相关的函数:

  • t.isInterrupted()

    非静态函数,读取中断标志位,不重置中断标志位。

  • Thread.interrupted()

    静态函数,给线程发送一个唤醒信号,如果是处于轻量级阻塞的线程收到唤醒信号后会被唤醒,重置中断标志位,并且抛出InterruptedException。

2.3.等待、唤醒

线程的等待状态是指线程由于一些原因先不向下执行,但暂时不放弃资源,只是稍作等待而已。等待和阻塞不同,阻塞是本来就不该执行,所以等待是可以发生在任何地方的,因此JDK给每个对象都设计了一个监视器锁(Monitor),这是Java虚拟机(JVM)底层为线程同步做出的支持。有了这个Monitor后JDK支持了线程在任何对象上先暂时等待,因为线程可以暂时躺在这个Monitor上。并给Object设计了如下api用来操作线程进行等待和唤醒:

  • wait(),等待。
  • notify(),唤醒。

在使用等待、唤醒时有两点注意事项:

  • 持有锁

    即wait()、notify()需要进行互斥,不可能一边notify(),一边wait()。

    代码示例:

  • 释放锁

    由于wait()是在同步代码块中执行的,wait()时要注意锁的释放,否则会死锁。

代码示例:

public class WaitNotifyDemo {

    private static final Object lock = new Object();
    private static boolean ready = false;

    public static void main(String[] args) {
        Thread producer = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Producer: Waiting for consumer...");
                lock.notify();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                ready = true;
            }
        });

        Thread consumer = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println("Consumer: Waiting for notification...");
                    lock.wait();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                if (ready) {
                    System.out.println("Consumer: Received notification, ready is true.");
                }
            }
        });

        consumer.start();
        producer.start();
    }
}

2.4.阻塞、唤醒

阻塞唤醒有工具类:

LockSupport.park(), LockSupport.unpark(Thread thread)

其实底层调的都是线程原语:

JDK操作线程阻塞用的都是这个原语,底层就是用native调的操作系统的接口:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1947632.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

代码随想录算法训练营day8 | 344.反转字符串、541.反转字符串 II、卡码网:54.替换数字

文章目录 344.反转字符串思路 541.反转字符串 II思路 卡码网:54.替换数字思路复习:字符串 vs 数组 总结 今天是字符串专题的第一天,主要是一些基础的题目 344.反转字符串 建议: 本题是字符串基础题目,就是考察 revers…

链式法则和自动求导

向量链式法则 说明: 1.第一个式子, y是标量,u是标量,x是n维向量 2.第二个式子,y是标量,u是k维向量,x是n维向量,所以y对u求导是k维的行向量,u对x求导是k行n列的矩阵&…

Node 版本控制工具 NVM 的安装和使用(Windows)

遇到了一个项目,前端的node版本很低,需要我去降低node版本才能下载依赖运行,我当然不是傻乎乎的降版本了,而是使用node版本控制工具 NVM。 NVM(Node Version Manager) nvm 是一个命令行工具,用于…

【OSS对象存储】Springboot集成阿里云OSS + 私有化部署Minio

【OSS对象存储】Springboot集成阿里云OSS 私有化部署Minio 一、摘要二、POM依赖三、配置文件四、表结构设计五、代码实现5.1 代码包结构5.2 API封装5.3 增删改查 六、扩展6.1 Minio配置https访问 一、摘要 掌握阿里云OSS、私有化部署Minio两种对象存储的使用方式运用工厂策略…

STM32-寄存器ADC配置指南

目录 输入方式: 模拟看门狗功能: ADC中断 配置一个Demo 设置时钟 自校准 通道选择 采样时间选择 转换模式选择 断续模式 启动转换 软件触发 外部触发 转换结束 关于DMA 模拟看门狗 ​编辑ADC数据位置​编辑 在STM32F中,ADC可…

FM与AM的特点

1.是什么? FM(调频):通过改变载波频率来传递信息AM(调幅):通过改变载波的振幅来传递信息 2.分别有什么特点? 抗干扰能力: FM:由于FM信号的传输不依赖于载波的…

c++初阶知识——string类详解

目录 前言: 1.标准库中的string类 1.1 auto和范围for auto 范围for 1.2 string类常用接口说明 1.string类对象的常见构造 1.3 string类对象的访问及遍历操作 1.4. string类对象的修改操作 1.5 string类非成员函数 2.string类的模拟实现 2.1 经典的string…

【CI/CD】docker + Nginx自动化构建部署

CI/CD是什么 CI/CD 是持续集成(Continuous Integration)和持续部署(Continuous Deployment)或持续交付(Continuous Delivery)的缩写,它们是现代软件开发中用于自动化软件交付过程的实践。 1、…

自动驾驶系列—智能巡航辅助功能中的路口通行功能介绍

自动驾驶系列—智能巡航辅助功能中的车道中央保持功能介绍 自动驾驶系列—智能巡航辅助功能中的车道变换功能介绍 自动驾驶系列—智能巡航辅助功能中的横向避让功能介绍 自动驾驶系列—智能巡航辅助功能中的路口通行功能介绍 文章目录 2. 功能定义3. 功能原理4. 传感器架构5. 实…

【Redis进阶】集群

1. 集群分片算法 1.1 集群概述 首先对于"集群"这个概念是存在不同理解的: 广义的"集群":表示由多台主机构成的分布式系统,称为"集群"狭义的"集群":指的是redis提供的一种集群模式&…

牛客JS题(二)直角三角形

注释很详细&#xff0c;直接上代码 涉及知识点&#xff1a; repeat格式化字符串 题干&#xff1a; 我的答案 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"></head><body><div classtriangle><…

C++树形结构(1 基础)

目录 一.基础&#xff1a; 1.概念&#xff1a; 2.定义&#xff1a; Ⅰ.树的相关基础术语&#xff1a; Ⅱ.树的层次&#xff1a; 3.树的性质&#xff1a; 二.存储思路&#xff1a; 1.结构体存储&#xff1a; 2.数组存储&#xff1a; 三.树的遍历模板&#xff1a; 四.信…

【BUG】已解决:NameError: name ‘python‘ is not defined

NameError: name ‘python‘ is not defined 目录 NameError: name ‘python‘ is not defined 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于…

【TortoiseGit】合并单个commit(提交)到指定分支上

0、前言 当我们用Git的时候经常用到多个分支&#xff0c;会经常有如下情况&#xff1a;一个dev分支下面会有多个test分支&#xff0c;而每个test分支由不同的开发者。而我们会有这样的需求&#xff1a; 当某个test分支完成了相应功能验证&#xff0c;就要把成功验证的功能代码…

【Git】上传代码命令至codeup云效管理平台

通过git命令上传本地代码库至阿里的codeup云效管理平台的代码管理模块&#xff0c;使用方便&#xff0c;且比github上传网络环境要求低&#xff0c;超大文件&#xff08;>100M&#xff09;的文件也可以批量上传&#xff0c;且上传速度喜人。 目录 &#x1f337;&#x1f33…

[Vulnhub] Acid-Reloaded SQLI+图片数据隐写提取+Pkexec权限提升+Overlayfs权限提升

信息收集 IP AddressOpening Ports192.168.101.158TCP:22,33447 $ nmap -p- 192.168.101.158 --min-rate 1000 -sC -sV Not shown: 65534 closed tcp ports (conn-refused) PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 6.7p1 Ubuntu 5ubuntu1.3 (Ubuntu Lin…

【NOI-题解】1009 - 数组逆序1162 - 数组元素的删除1211 - 数组元素的插入1161. 元素插入有序数组1159. 数组元素的移动

文章目录 一、前言二、问题问题&#xff1a;1009 - 数组逆序问题&#xff1a;1162 - 数组元素的删除问题&#xff1a;1211 - 数组元素的插入问题&#xff1a;1161. 元素插入有序数组问题&#xff1a;1159. 数组元素的移动 三、感谢 一、前言 本章节主要对数组问题中数组元素移…

昇思25天学习打卡营第23天 | 基于MindSpore的红酒分类实验

学习心得&#xff1a;基于MindSpore的红酒分类实验 在机器学习的学习路径中&#xff0c;理解和实践经典算法是非常重要的一步。最近我进行了一个有趣的实验&#xff0c;使用MindSpore框架实现了K近邻&#xff08;KNN&#xff09;算法进行红酒分类。这个实验不仅加深了我对KNN算…

Jenkins+Gitlab持续集成综合实战

一、持续集成应用背景&#xff1a; DevOps&#xff1a;&#xff08;英文Development&#xff08;开发&#xff09;和Operations&#xff08;技术运营&#xff09;的组合&#xff09;是一组过程、方法与系统的统称&#xff0c;用于促进开发&#xff08;应用程序/软件工程&#…

设计模式|观察者模式

观察者模式是一种行为设计模式&#xff0c;它定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对象。当主题对象发生变化时&#xff0c;它的所有观察者都会收到通知并更新。观察者模式常用于实现事件处理系统、发布-订阅模式等。在项目中&#xff0c…