多线程的操作

1、Thread类

1.1 Thread类的作用

上篇博文中我们了解了线程与操作系统的关系:线程是操作系统中的概念,操作系统内核实现了线程这样的机制, 并且对用户层提供了一些 API 供用户使用,Java 标准库中 Thread 类可以视为是对操作系统提供的 API 进行了进一步的抽象和封装

既然Thread类可以视为对操作系统提供的API进行了进一步的抽象和封装,那么我们就可以通过Thread类来操作线程

1.2 Thread类常见的构造方法

方法

说明

Thread()

创建线程对象

Thread(Runnable target)

使用 Runnable 对象创建线程对象

Thread(String name)

创建线程对象,并命名

Thread(Runnable target,String name)

使用Runnable对象创建线程对象,并命名

Thread(ThreadGroup group,Runnable target)

线程可以被用来分组管理,分好的组即为线程组

1.3 Thread几个常见属性

属性

获取方法

ID

getId()

名称

getName()

状态

getState()

优先级

getPriority

是否后台线程(守护线程)

isDaemon()

是否存活

isAlive()

是否被中断

isInterrupted()

守护线程和非守护线程:

是否是“后台线程”也称为 是否是“守护线程”

是否是“守护线程”,可以分为:

  1. 后台线程(守护线程),不会阻止进程的结束,即使后台线程的工作没有做完,进程也是可以结束的

  1. 前台线程(非守护线程),会阻止进程的结束,如果前台线程的工作没有做完,进程是不能结束的

我们平时手动创建的线程,默认都是前台线程,包括 main 线程在内

jvm自带的线程都是后台线程

我们通常是可以通过手动将前台线程设置为后台线程的,设置方法 setDaemon

2、 启动一个线程


public class Demo {public static void main(String[] args) {Thread thread = new Thread(()->{//任务描述System.out.println("hello run");});//线程创建thread.start();}
}

对象名.start():开启一个线程

如果光创建一个Thread对象,不进行start,操作系统内核中是否有线程呢?


Thread thread = new Thread(()->{//任务描述System.out.println("hello run");
});

答:没有,只有 对象名.start() 才会在让内核创建一个 PCB,此时这个 PCB 才表示一个真正的线程

  • 当创建了一个 Thread 对象,并没有调用 start 方法之前,如果调用 isAlive 就是 false

  • 调用 start 方法后线程正在执行,如果调用 isAlive 就是 true

  • 如果内核里线程把 run 执行完后,此时线程就会销毁,pcb也就会随之释放,那么此时 isAlive 就是 false

isAlive 是在判断,当前系统里面的这个线程是不是真的存在

3、 中断一个线程

中断不是让线程立即停止,而是通知线程,你应该要停止了。是否真的停止,还是需要取决于线程这里的具体代码的写法

3.1 如何中断线程

3.1.1 使用标志位来控制线程是否要停止


public class ThreadDemo {public static Boolean flag = true;public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{while (flag) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);//抛出异常}}});thread.start();Thread.sleep(3000);flag = false;}
}

自定义变量这种方式,不能及时响应,尤其是在 sleep 休眠的时间比较久的时候

这个代码就是修改 flag,让thread线程结束,thread线程是否真的结束完全取决于thread线程内部的代码,代码里通过flag控制循环的。因此这里只是告诉这个线程结束,这个线程是否要结束以及啥时候结束都是线程内部自己代码来决定了

3.1.2 使用Thread自带的标志位,来进行判断


public class ThreadDemo {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{while (!Thread.currentThread().isInterrupted()) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();//打印出异常堆栈信息}}});thread.start();Thread.sleep(3000);thread.interrupt();//终止线程}
}

方法

说明

public void interrupt()

中断对象关联的线程,如果线程正在阻塞,则以异常方式通知,否则设置标志位

public static boolen interrupted()

判断当前线程的中断标志位是否设置,调用后清除标志位

public boolean isInterrupted()

判断对象关联的线程的标志位是否设置,调用后不清楚标志位

public static Thread currentThread()

返回当前线程对象的引用

上述代码的运行结果:

上述这个异常是调用interrupt触发的,那为什么异常被触发后,线程依旧在执行咧?

调用 interrupt 会做两件事:

  1. 把线程内部的标志位设置成 true

  1. 如果线程在进行 sleep,会触发异常,把sleep唤醒。唤醒的时候,把刚才设置的这个标志位,在设置回 false(清空标志位)

3.2 中断线程的情况

上述我们提到了中断不是让线程立即停止,而是通知线程,你应该要停止了。是否真的停止,还是需要取决于线程这里的具体代码的写法

举例说明:

3.2.1 线程Thread忽略终止请求


public class ThreadDemo {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{while (!Thread.currentThread().isInterrupted()) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();//打印异常信息,不做其他处理}}});thread.start();Thread.sleep(3000);thread.interrupt();}
}

3.2.2 线程 Thread 稍后响应终止请求


public class ThreadDemo {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{while (!Thread.currentThread().isInterrupted()) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();//等待0.5s后,线程终止try {Thread.sleep(500);} catch (InterruptedException ex) {ex.printStackTrace();}break;}}});thread.start();Thread.sleep(3000);thread.interrupt();}
}

3.2.3 线程Thread立即响应终止请求


public class ThreadDemo {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{while (!Thread.currentThread().isInterrupted()) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();break;//线程直接终止}}});thread.start();Thread.sleep(3000);thread.interrupt();}
}

4、等待一个线程 join

等待一个线程:对象名.join( )

线程是一个抢占式执行,随机调度的过程。等待线程要做的事情,就是控制两个线程的结束顺序

方法

说明

public void join()

一直等,直到线程结束

public void join(long millis)

等到一定时间

public void join(long millis,int nanos)

等到一定时间,但可以更高的精度


public class ThreadDemo {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{for (int i = 0; i < 100; i++ ) {System.out.println("hello");try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}});thread.start();thread.join();//join:main线程等待thread线程结束之后在往下执行main线程剩下的内容for (int i = 0; i < 100; i++) {System.out.println("main");Thread.sleep(1000);}}
}

代码解析:本身执行完 start 之后,thread 线程和 main 线程就并发执行,分头行动。main 继续往下执行,thread也会继续往下执行,当main遇到thread.join就会发生阻塞,一直阻塞到thread线程结束,main线程才会从 join 中恢复回来,才能继续往下执行。

经过 join 的控制,thread 线程肯定会比main 线程先结束

问题:假设执行 join 的时候,thread 线程已经结束了,此时的 join 会咋样?

答:如果执行 join 的时候,thread 已经结束了,join 就不会阻塞,会立即返回

5、休眠当前的线程

我们通常采用 sleep 让线程休眠,休眠的本质就是让这个线程不参与调度(也就是不去cpu上执行),等到休眠时间到了在参与调度

操作系统内核:

就绪队列:这个列表里面的PCB都是“随叫随到”,就绪状态

当就绪队列中的线程 A 调用 sleep 就会进入休眠的状态,把 A 从上述就绪列表中拎出来,放在另一个链表中,这个链表中的PCB,都是“阻塞状态”,暂时不参与 CPU 的调度执行

一旦线程进入阻塞状态,对应的PCB就进入阻塞队列了,此时就暂时无法参与调度了

只有对应的PCB回到就绪状态,才会重新加入调度序列,一般在唤醒之后不会立即执行,因为考虑调度的开销

PCB 是使用链表来组织的,实际上并不是一个简单的链表,而是一系列以链表为核心的数据结构

6、线程的状态

线程的状态是根据线程的调度情况来进行描述的 ,在Java中对线程的状态进行了如下细化:

  • 初始状态(NEW):线程被创建后,就处于这个状态。这时,它还没有开始运行。
  • 运行状态(RUNNABLE):当线程被启动后,就转为运行状态。这时,它正在Java虚拟机中运行。需要注意的是,即使线程处于运行状态,也不一定意味着它正在执行CPU计算。
  • 阻塞状态(BLOCKED):如果线程需要等待监视器锁才能继续执行,它就会进入阻塞状态。例如,当一个线程试图获取一个内部的对象锁,而这个锁被其他线程持有,那么这个线程就会变成阻塞状态。
  • 等待状态(WAITING):进入等待状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
  • 超时等待状态(TIMED_WAITING):这是等待状态的一种特殊形式,线程在此状态下会等待特定的时间间隔。
  • 终止状态(TERMINATED):当线程完成执行或因异常而结束时,就会进入这个状态。

举例说明:假设你想上厕所,首先是你得想上厕所(相当于NEW状态) ,所以你得去厕所上,进入厕所后你才能上(相当于RUNNABLE状态),当你还未进入厕所时可能你女朋友在里面上厕所把门锁上了,所以你得等,等她上完把门打开你才能进去上厕所(相当于BLOCKED状态),还有可能你女朋友上完后厕所有点臭,你想等个两分钟后等味道散了在去上(相当于TIME_WAITING状态),还有可能厕所坏了,你得等修厕所的师傅修好,跟你说了你才能上(相当于WAITING状态),等你上好后(相当于TERMINATED状态)

注:一个线程对象只能 start 一次 

这里主要给大家演示 NEW、RUNNABLE、TERMINATED :

public class Demo {public static void main(String[] args) throws InterruptedException {Thread t = new MyThread();//创建一个线程System.out.println("状态" + t.getState());t.start();//启动一个线程Thread.sleep(2000);System.out.println("状态" + t.getState());t.interrupt();//中断一个线程Thread.sleep(2000);System.out.println("状态" + t.getState());}
}
class MyThread extends Thread {@Overridepublic void run() {while (!Thread.currentThread().isInterrupted()){System.out.println("hello thread");try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();break;}}}
}

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

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

相关文章

51单片机应用开发(进阶)---串口接收字符命令

实现目标 1、巩固UART知识&#xff1b; 2、掌握串口接收字符数据&#xff1b; 3、具体实现目标&#xff1a;&#xff08;1&#xff09;上位机串口助手发送多字符命令&#xff0c;单片机接收命令作相应的处理&#xff08;如&#xff1a;openled1 即打开LED1;closeled1 即关…

3-5 C常用的字符串库函数

1.0 字符串库函数 strlen()函数用于返回字符串的长度&#xff0c;不包括结尾\0 uint32_t strlen(char *str) {uint32_t len 0;while (str[len] ! \0){len;}return len; } 编译器在处理字符串时&#xff0c;会自动的在数据末尾添加ASCI码“0对应十进制0&#xff0c;便于程序对…

python语法基础---正则表达式(补充)

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 上一篇文章中&#xff0c;我们讲到了贪婪匹配和非贪婪匹配&#xff0c;我们在这篇文章中&#xff0c;主要讲的就是贪婪匹配和非贪婪匹配的剩下的部分&#xff0c;话不多说&#x…

如何在谷歌浏览器中设置网络代理

在当今的网络环境中&#xff0c;使用代理服务器可以增强您的隐私和安全性。如果您希望在谷歌浏览器中设置网络代理&#xff0c;本文将为您提供详细的步骤指南。此外&#xff0c;我们还会简要介绍如何使用谷歌浏览器的任务管理器、查看Cookies以及更换侧边栏位置&#xff0c;以便…

【AI系统】MobileNet 系列

MobileNet 系列 在本文会介绍 MobileNet 系列&#xff0c;重点在于其模型结构的轻量化设计&#xff0c;主要介绍详细的轻量化设计原则&#xff0c;基于这原则&#xff0c;MobileNetV1 是如何设计成一个小型&#xff0c;低延迟&#xff0c;低功耗的参数化模型&#xff0c;可以满…

分层架构 IM 系统之 Router 假在线分析

通过对分层架构 IM 系统的分析&#xff0c;Router 的核心职责是作为中央存储记录在线客户端与 Entry 节点之间的映射关系&#xff0c;在本质上 Router 是一个内存数据库。 客户端已经离线&#xff0c;Entry 还未感知&#xff0c;或者 Entry 已经感知并且切断了连接&#xff0c;…

04 创建一个属于爬虫的主虚拟环境

文章目录 回顾conda常用指令创建一个爬虫虚拟主环境Win R 调出终端查看当前conda的虚拟环境创建 spider_base 的虚拟环境安装完成查看环境是否存在 为 pycharm 配置创建的爬虫主虚拟环境选一个盘符来存储之后学习所写的爬虫文件用 pycharm 打开创建的文件夹pycharm 配置解释器…

在Java的xml的sql语句里面的某一个参数是list集合的时候

经常在Java里面&#xff0c;遇到这样的问题&#xff0c;sql的一个查询语句&#xff0c;它的某一个参数是一个List集合&#xff0c;然而&#xff0c;在xml.mapper文件里面的时候&#xff0c;不知道如何去组成这个查询语句&#xff0c;不知道兄弟们是否经常忘记如何去写这个语句&…

pdf转word/markdown等格式——MinerU的部署:2024最新的智能数据提取工具

一、简介 MinerU是开源、高质量的数据提取工具&#xff0c;支持多源数据、深度挖掘、自定义规则、快速提取等。含数据采集、处理、存储模块及用户界面&#xff0c;适用于学术、商业、金融、法律等多领域&#xff0c;提高数据获取效率。一站式、开源、高质量的数据提取工具&…

一文讲清楚ROS2中多线程、并发、回调组的概念和基础使用

前言 在机器人开发中&#xff0c;多线程的使用司空见惯。ROS2借助executor类帮助开发者简化多线程的使用&#xff0c;但是还是得先把基本概念搞清楚&#xff0c;才能正确的使用。本文解释了ROS1和ROS2中的并发/多线程概念&#xff0c;并且给出了ROS2版本一些实际例子帮助理解。…

《向量数据库指南》——Mlivus Cloud:OPPO的向量数据库选型秘籍

Why Mlivus Cloud? —— 向量数据库选型的深度剖析与实战分享 在当今这个数据驱动的时代,向量数据库作为处理非结构化数据的重要工具,正逐渐受到业界的广泛关注。OPPO,作为全球知名的智能手机制造商,也在这场技术变革中积极探索和实践。他们在向量检索的道路上,从最初的…

MySQL:锁机制

锁是计算机协调多个进程或线程并发访问某一资源的机制&#xff08;避免争抢&#xff09;。 在数据库中&#xff0c;除传统的计算资源&#xff08;如 CPU、RAM、I/O 等&#xff09;的争用以外&#xff0c;数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效…

HTMLCSS :动态效果的玫瑰花

这段代码通过 HTML 和 CSS 的结合&#xff0c;创建了一个动态的花朵效果&#xff0c;展示了 CSS 动画和定位的强大功能。 演示效果 HTML&CSS <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equ…

深入浅出:SOME/IP-SD的工作原理与应用

目录 往期推荐 相关缩略语 SOME/IP 协议概述 协议介绍 SOME/IP TP 模块概述和 BSW 模块依赖性 原始 SOME/IP 消息的Header格式 SOME/IP-SD 模块概述 模块介绍 BSW modules依赖 客户端-服务器通信示例 Message 结构 用于SD服务的BSWM状态处理 往期推荐 ETAS工具…

【AI系统】EfficientFormer 系列

EfficientFormer 系列 本文主要介绍一种轻量化的 Transformer 结构&#xff0c;在获得高性能的同时&#xff0c;能够保持一定的推理速度。以延迟为目标进行优化设计。通过延迟分析重新探讨 ViT 及其变体的设计原则。 EfficientFormer V1 模型 EfficientFormer V1:基于 ViT 的…

vue3 vite ts day1

创建项目&#xff1a; npm init vitelatest 来创建项目 第二布&#xff1a; y 第三步&#xff1a;project name &#xff1a;项目名称 第四步&#xff1a;select a framework 选择框架 熟悉那种选择那种&#xff0c;当前选择vue 第五步&#xff1a;select a variant&…

dbus接口方法的variant类型传参详解

python实现c++中so库调用及dbus服务开发-CSDN博客 之前写的这篇博文介绍了如何创建一个dbus服务,但是注册的接口方法的入参还是比较简单的,实际上dbus的参数类型有很多种,调用方式也有多种,我们来逐一介绍下。 其实基础数据类型,如字符串、整型、浮点型、布尔型等大多数…

路由策略一

目录 匹配C类网络全部的子网 ip ip-prefix 1 permit 192.0.0.0 3 greater-equal 25 less-equal 32 ACL的组成&#xff1a; ACL编号&#xff1a;在网络设备上配置ACL时&#xff0c;每个ACL都需要分配一个编号&#xff0c;称为ACL编号&#xff0c;用来标识ACL。不同分类的AC…

摩尔线程 国产显卡 MUSA 并行编程 学习笔记-2024/12/03

Learning Roadmap&#xff1a; Section 1: Intro to Parallel Programming & MUSA Deep Learning Ecosystem&#xff08;摩尔线程 国产显卡 MUSA 并行编程 学习笔记-2024/11/30-CSDN博客&#xff09;UbuntuDriverToolkitcondapytorchtorch_musa环境安装(2024/11/24-Ubunt…