多线程(2)

news/2024/4/26 1:42:17/文章来源:https://blog.csdn.net/mu_tong_/article/details/128092087

文章目录

  • 前言 :
  • 1.Thread类 :
    • 1.1 Thread类常见的构造方法
    • 1.2 Thread的几个常见属性
    • 1.3 中断一个线程
    • 1.4 等待一个线程-join()
    • 1.5 获取当前线程引用
    • 1.6 休眠当前线程
  • 2.线程状态

前言 :

简单回顾上文知识点

上文我们了解了 线程是为解决并发编程引入的机制.

知道了线程相比于进程来说更轻量 ( 创建线程比创建进程开销更小,销毁进程比销毁进程 开销更小, 调度线程比调度进程开销更小) 。

另外我们的进程是包含线程的 , 所以同一个进程中的诺干个线程之间共享同一份内存资源和文件描述符表,

虽然进程之间是共享同一份资源 , 但是线程之间都是可以独立调度执行的,且每个线程都有自己的状态 / 优先级 / 上下文 / 记账信息 .

除了以上这几点 ,还总结果两点 :

1.进程是操作系统分配的基本单位

2.线程是操作系统调度执行的基本单位

通过 Thread 类 创建线程的几种方法

1.继承Thread 重写 run

2.实现 Runnable 重写 run

3.使用匿名内部类, 继承 Thread

4.使用匿名内部类,实现 Runnable

5.使用lambda 表达式

注意 : 这里是离不开 Thread的, 上面的几种方式 只是使用了不同的方式来描述 Thread里的任务是啥 。

同时这里的几种方法创建出来的线程是一样的 .

最后回顾一下 Thread 的 run 和 start 的区别

run : 只是一个普通的方法, 描述线程执行的任务是上面

start : 当我们调用 start 方法时才会去创建线程, 并执行run里面的方法.

下面就来开始本文的学习 :

上文 我们已经通过 Thread类创建了我们的线程, 下面就来了解一下 Thread类 和 方法

1.Thread类 :


概念 :

Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联。

Thread 类的对象就是用来描述一个线程执行流的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理

1.1 Thread类常见的构造方法

方法说明
Thread()创建线程对象
Thread(Runnable target)使用 Runnable 对象创建线程对象
Thread(String name)创建线程对象,并命名
Thread(Runnable target, String name)使用 Runnable 对象创建线程对象,并命名
【了解】Thread(ThreadGroup group,Runnable target)线程可以被用来分组管理,分好的组即为线程组,这个目前我们了解即可


这里 Thread(String name) 和 Thread(Runnable target , String name) 与之前相比只是多了一个参数 name , 主要的作用就是为我们的线程起名,方便我们后面进行调试 , 这里线程的默认名字 为 thread-0 之类的…

如 thread - 1, 2 , 3 等, 线程一多就很难分辨,所以命名操作比较重要。


下面就来演示一下 :


图一 : 创建线程, 并将线程命名为 mythread , 并启动
在这里插入图片描述

下面就可以通过上文所讲的 jconsole 来查看我们的线程, 这里就不赘述如何找到jdk的jconsole

图二 :

在这里插入图片描述


注意 :

在这里插入图片描述


常见的构造方法看完来看看我们的Thread的常见属性

1.2 Thread的几个常见属性

属性获得方法
IDgetId()
名称getName()
状态getState() : 线程状态
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()


getName() : 这里获取到的就是我们再构造方法里面取的名字


getState() : 线程状态


注 :java里面的线程状态要比操作系统原生的状态更丰富一点


getPriority() : 这个可以获取线程的优先级 ,也可以设置,但设置了也没有啥用


isDaemon() : 这里是判断是否为守护线程,这里翻译成守护线程可能会让人尝试误会,所以这里更推荐说成是否为后台线程 :

那么啥是后台线程呢 ?

简单来说 : 到了 中午 12点 ,吃饭,但我们手头上有一件事情,比较重要 紧急,必须做完才能去吃 , 这里就是前台线程,必须等线程任务执行完才能结束线程.

后台线程 : 同样是 12 点 吃饭,手头上同样有一件事情,但是不那么 重要,紧急 ,此时就可以直接放下手中的事情,去吃饭. 就是说后台线程 ,不会因为线程的工作 而导致线程不结束.


前台线程 :会阻止进程结束,前台线程的工作没有做完,进程是完成不了的
在这里插入图片描述


后台线程 : 不会阻止进程结束 , 后台线程工作没做完,进程也可以结束的.

注意 : 代码里面手动创建的线程,默认都是前台线程, 包括 main默认也是前台线程。

其他 jvm 自带的线程都是后台的, 这里我们也可以使用 setDaemon 设置成后台线程.


演示 通过 setDaemon 将 t 线程改为 我们的后台线程

在这里插入图片描述


isAlive() : 是否存活


这里判断的系统里面的线程是否存活


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


另外 : 多个线程再微观上可能是并行的(多个核心), 也可能是并发的(一个核心) ,宏观上感知不到(应用程序) , 所以我们看到的就始终是随机执行,抢占式调度的.


属性看完下面来看一下我们如何中断一个线程

1.3 中断一个线程


注意 : 这里中断的意思 ,不是让线程立刻就停止,而是通知线程 ,你应改要停止了,是否真的停止,取决于线程这里具体的写法 .


举个简单的例子 :

这里我们处于打游戏 的时候, 突然 母亲叫我们去超市带一瓶酱油 此时我们有三种做法

1.放下游戏,立刻就去

2.打完这把,再去,稍后处理

3.假装没听见,就完全不处理


此时 这里是直接去还是拖一会,还是直接装傻充愣 不去都是我们自己的选着 。


在我们线程中 就有两种比较典型的做法


1.通过共享的标记来进行沟通

在这里插入图片描述


2.调用 interrupt() 方法来通知


上面自定义变量的方法 会有一个很大的缺点, 它不能及时响应, 尤其是在 sleep 休眠的时间比较久就的时候 .

在这里插入图片描述


这里我们就可以使用 Thread 自带的标志位,来进行判断


图一 :
在这里插入图片描述


图二 :

在这里插入图片描述


图三 :

在这里插入图片描述


注意 : 这里是 sleep 清空我们的标志位 .


之前我们说过 线程的执行的随机调度的,所以我们并不能够知道谁前谁后,正因为它的不可预期性,这里我们普变更喜欢能够预期的,知道谁先执行谁后执行 , 这里我们就可以通过 等待线程,来控制两个线程的结束顺序.

1.4 等待一个线程-join()


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


好比 :放学接娃, 原本 5点放学, 我们 4.55 到,此时我们就需要等待孩子放学,到了时间我们就可以将孩子接走,如果 我们 5.05到,那就不是我们等孩子了而是孩子等我们, 当我们到了就直接将孩子带走即可.


另外 我们直接使用 join() 会有一个问题,就是死等的问题, 啥是死等呢 ?

就相当于当于一条舔狗,一直舔一个女神,不管多久就舔她一个,这里就可以看成死等 , 没有舔到 , 就一直就 舔。

这里就非常不好,即便是舔狗也是有原则的,也是有底线的,舔不到就不舔了,换一个。


join 为了解决死等的问题 , 就提供了另外一个版本 ,即 join(long millis) 此时就可以指定等待的时间, 这里的参数就是线程能够等待的最长时间 , 当时间到达了 这个等待的时间,就不会在等待了 直接执行下面的操作。

1.5 获取当前线程引用

方法说明
public static Thread currentThread();返回当前线程对象的引用


这个方法在 中断一个线程就出现了,到这里因该是比较熟悉的 ,所以这里就直接一笔带过 。

在这里插入图片描述


题外话:

public static Thread currentThread() ;

这里我们一般都称 被 static 修饰的方法 是静态方法但是静态方法这个名字不太好 , 更推荐 称为 类方法 。


类方法 : 调用这个方法,不需要实例,直接通过类名来调用。

如果 : Thread t = new Thread() Thread 是 类 , t 是实例 , 那么 对于 currentThread() 方法, 就可以直接 Thread.currentThread() 调用 (返回值正是这个引用指向的对象), 而不一定非得

t.currentThread() , 这里 直接使用类名调用 就是类方法 。

另外 : 通过 t.currentThread() 也是可以调用的, 但这么做,本质上 还是通过实例找到类, 再通过类名的方法调用. (javase 语法中也提过这个,这样写编译器会报警告).

1.6 休眠当前线程

方法说明
public static void sleep(long millis) throws InterruptedException休眠当前线程 millis毫秒
public static void sleep(long millis, int nanos) throws InterruptedException可以更高精度的休眠


线程休眠 : 本质上就是让这个线程不参与调度了(不去CPU上执行) 。

好比之前进程中的 海王例子 : 不是说海王谈了3个女朋友 A B C , 假如 B 去出差了 , 此时海王就没有机会去和 B约会了, 那么 B 就相当于暂时不参与调度了.

此时 只有 A 和 C 能进行调度 ,当 B回来之后 ,才能重新参与调度 .

在这里插入图片描述

2.线程状态


之前在 进程的那篇文章,说过状态 是进程的一种属性但是这种说法并不是太严谨, 为啥之前说呢?

还是哪一个点, 之前的文章是针对进程中只有一个线程的情况,所以才去这么说的, 但大多数情况下一个进程对应着一组PCB(每个PCB对应这一个线程) , 此时操作系统调度线程, 就可以通过线程的状态来判断是否需要调度 就绪就直接调用 ,阻塞就换一个处于就绪的线程 . 所以以后听到状态更应该是线程的属性了, 那么后面谈到状态都应该先考虑线程。

在这里插入图片描述


我们 主要讨论 两种状态 1.就绪, 2. 阻塞 , 但是 java 对于线程的状态,进行了细化操作 , 也就分出来了 6中状态, 下面就来看看.

1.NEW :创建了 Thread对象, 但是还没调用 start(操作系统内核还没创建对应的PCB)

2.TERMINATED : 表示内核中的PCB 已经执行完毕了, 但Thread对象还在.

3.RUNNABLE : 可以运行的 (注意 : 这里叫 RUNNABLE ,而不是 RUNNING 正在运行

这里有两种情况

a : 正在CPU上执行的

b : 在就绪队列里,随时可以去CPU上执行 .


4.WAITNG

5.TIMED_WAITING

6.BLOCKED


这里 4 , 5 , 6 都是阻塞 , 都是表示 线程 PCB正在阻塞队列中 , 这几种状态 都是不同原因的阻塞.

在这里插入图片描述


简单画一个 线程的转化 :

在这里插入图片描述


另外 这里也有 复杂的 :个人感觉简单的图足够 了 .

在这里插入图片描述


下面就来通过 代码 来触发一下这几个状态 :


1.NEW :创建了 Thread对象, 但是还没调用 start(操作系统内核还没创建对应的PCB)

在这里插入图片描述


2.TERMINATED : 表示内核中的PCB 已经执行完毕了, 但Thread对象还在.

在这里插入图片描述

补充 :

TERMINATED 这个状态其实并没有啥用 , 因为一旦内核里的线程 PCB 消亡了, 此时 代码中 t 对象 也就没啥用了。

为啥存在呢 ?

其实迫不得已 , java中对象的生命周期,自有其规则,这个生命周期和系统内核里面的线程并非完全一致 , 内核的线程释放的时候,无法保证 Java 代码中 t 对象也立即释放 .

因此 , 势必就会存在 ,内核的 PCB 没了,但是代码中的 t 还存在的情况 , 此时就需要通过特定的状态,来将 t 对象表示成 “无效的状态” 。

另外这里 不能 重新 start , 也就是不能重新创建线程 , 这里一个线程 只能start 一次 .


3.RUNNABLE : 可以运行的 (注意 : 这里叫 RUNNABLE ,而不是 RUNNING 正在运行


这里有两种情况

a : 正在CPU上执行的

b : 在就绪队列里,随时可以去CPU上执行 .

在这里插入图片描述


如果再 run 里面写了 sleep 之类 的方法 让线程阻塞了 , 就不是 RUNNABLE


4.TIMED_WAITING

在这里插入图片描述


5.WAITNG

6.BLOCKED

最后的这两个 后面说 .

到此 Thread 类常见的方法 和 线程的状态就差不多说完了, 下面我们来通过代码来看看 :

单个线程和多个线程之间的执行速度的差别 (CPU 密集的程序中差别是非常明显的) .


小补充 :

其实 程序主要分为 :

CPU 密集 : 包含了大量的加减乘除等算术运算

IO 密集 : 涉及到读写文件, 读写控制台,读写网络


这里就可以假设一个场景 : 有一个运算量非常大的任务 , 这里就分别通过进程 (单个线程) 和 多线程分别执行,观察他们开始执行时间 和 结束程序时间之差。


1.使用单个线程

在这里插入图片描述

2.使用两个线程

在这里插入图片描述


对比一下 : 使用单个线程 执行的时间为 484ms , 使用两个线程执行的时间是 270ms , 可以看到时间缩短的很明显。

但是就有一个问题 :为啥不是正好缩短一半?

答案 : 因为多线程可以更充分的利用到多核心 cpu 的资源,因此使用多线程的时间会快 ,但是 我们并不能知道 t1 和 t2 是分布再两个 CPU上执行还在一格cpu上 先执行 t1 然后 执行 t2 ,绕一圈回来 又执行t1. (这里就是并行和并发)

另外一点我们的线程调度 自身也是又时间消耗的.

所以这的时间就很难缩短到一半 。


所以 : 多线程 在这种CPU密集型的任务中,有非常大的作用,可以充分的利用 CPU 的多核资源,从而加快程序的运行效率


另外 : 并不是使用多线程 就能一定提高效率

还需要考虑 1. 是否是多核 , 2. 当前核心是否空闲(如果CPU 这些核心都满载了,这个时候启动跟多的线程也就没啥用)。

上面说 多线程 在 密集型程序有明显的作用, 其实多线程在 IO密集型的任务中,也是有作用的 .

举例 : 在日常使用的一些程序中,经常会看到 “程序未响应” (如 :启动 某款程序 ) 为啥呢 ?

因为 程序 进行了 一些耗时 的 IO 操作 (比如打开 dota2 启动 加载数据文件 ,就涉及到了 大量的读硬盘操作 ) , 阻塞了界面响应 ,这种情况下使用多线程也就可以有效改善(一个线程赋值IO , 另外一个线程用来响应用户的操作).

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java数据审计工具:Envers and JaVers比较

在Java世界中,有两种数据审计工具:Envers和JaVers。 Envers已经存在了很长时间,它被认为是主流。 JaVers提供全新的方法和技术独立性。 如果您考虑哪种工具更适合您的项目,本文是一个很好的起点。 本文分为三个部分。首先&#x…

[附源码]计算机毕业设计springboot餐馆点餐管理系统

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

【新知实验室-TRTC开发】实时音视频之欢度世界杯

目录 一、什么是TRTC 二、用5分钟跑通一个demo 1、开通腾讯云-TRTC 2、获取demo必须的两把钥匙 2.1输入应用名称 2.2下载对应的源码包(手机、web、小程序等) 2.3拿到钥匙 2.4完成 三、搭建一起看世界杯应用 1、解压源码(耗时30S&#x…

[附源码]计算机毕业设计springboot房屋租赁系统

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

MySQL为自动编号的字段赋值

insert users values(NULL,ming,fasdfasdfasd,22,1); 或者 insert users values(DEFAULT,ming,fasdfasdfasd,22,1);

网络的根基

hi 大家好,上个周末带小伙伴,一起复习了一遍网络协议,对网络协议的核心知识进行梳理,希望大家早日掌握这些核心知识,打造自己坚实的基础,为自己目标慢慢积累,等到自己春天的到来。详细点击查看…

zabbix拓扑图和聚合图形

目录 一、环境准备 1、搭建zabbix基础环境 2、创建被监控主机 二、拓扑图 1、拓扑图作用 2、拓扑图绘制步骤 三、聚合图形 1、聚合图形的作用 2、创建聚合图形 一、环境准备 1、搭建zabbix基础环境 zabbix基础环境部署参照:zabbix基础环境部署_桂安俊kyli…

Day14--商品详情-渲染商品详情的数据并优化详情页的显示

提纲挈领: 那么如何在小程序中将这些html的字符串渲染成这莫好看的结构呢? 官方文档:【使用uni-ui组件库中的rich-text组件】 1.渲染商品详情信息 我的操作: 1》在页面结构中,使用 rich-text 组件,将带有…

计算机网络第五章知识点回顾(自顶向下)

1. 网络层控制面 1.1 网络层功能 1.2选路问题 选路问题的描述: 给定一组路由器和连接路由器的链路,寻找一条从源路由器到目的路由器的最佳路径。 1.3 什么是最佳路径? 1.4 图抽象 1.5 选路算法分类 1.6 链路状态(LS&#xff0…

[附源码]计算机毕业设计springboot飞越青少儿兴趣培训机构管理系统

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

手把手教你构建一个前端路由

涉及知识点:location对象、history对象 文章目录基础概念什么是路由如何实现前端路由涉及问题前端路由实现方式1. hash方式2. history方式3. debug:本地起服务报错扩展:封装路由类Routerhashhistory基础概念 什么是路由 路由是一组映射关系…

51单片机学习笔记4 新建工程及点亮LED实战

51单片机学习笔记4 新建工程及点亮LED实战一、使用keil新建工程二、项目设置1. 点击魔术棒,钩选Output-Create Hex File2. 设置仿真器三、编写代码1. 尝试编译代码2. 点亮LED的代码3. GPIO引脚介绍4. GPIO内部结构P0端口:P1 端口四、软件仿真一、使用kei…

[附源码]SSM计算机毕业设计校园爱心支愿管理系统JAVA

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

台积电跪舔美国,日本却醒悟了而选择独立发展芯片产业

近期台积电大举包机10架将精英人才和设备转往美国引发争议,然而这个时候日本却选择了独立发展芯片产业的道路,摆脱美国的限制,显然日本清醒地认识到依赖美国不会有好结果。台积电之前还在左右摇摆,希望既能继续获得美国芯片的订单…

字符串压缩(一)之ZSTD

一、zstd压缩与解压 ZSTD_compress属于ZSTD的Simple API范畴,只有压缩级别可以设置。 ZSTD_compress函数原型如下: size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel) ZSTD_decompress函数原…

全网首发克莱斯勒东南大捷龙jeep道奇DIY数码碟盒增加USB和蓝牙播放音乐功能使用原车接口无损改装

文章目录前言碟盒功能1、设计指标3、外观设计4、PCB设计5、程序设计6、调试7、大捷龙车机尾插接口定义公头东南大捷龙车机白色插头模块与白色插头连接方法8、安装方法9、 使用方法9.1 CD车机按钮功能定义11、 联系我前言 ​ 之前写过四篇关于车机增加音频输入的方法。 1、07宝…

水电站下泄生态流量监控解决方案-智能监测生态流量遥测终端-水电站流量监测站

平升电子水电站下泄生态流量监控解决方案-智能监测生态流量遥测终端-水电站流量监测站是一款集人机交互、视频叠加、4G路由、数据采集、逻辑运算与远程传输功能于一体的多媒体智能终端设备。 此款产品为水电站生态流量监测项目的专用产品,便于监管单位及时掌握水电…

农村城镇面板数据集:地级市人均消费与支出2012-2019各省农村数据2013-2019

1、2002-2019年地级市人均消费与支出数据 1、数据来源:wind 2、时间跨度:2012-2019 3、区域范围:287个地级市 4、指标说明: 包含以下四个指标:人均可支配收入(农村)、人均可支配收入&#…

Python中的dump() 、load()和dumps()、loads()使用及示例

Python中的dump() 、load()和dumps()、loads() 结论: 1.不加s的标识对json文件的读写,将内存中值读取写入到json后缀文件,或者将json后缀文件中内容读取到内存 2.加了s的主要是字符串类型和其他数据类型的互转 JSON(JavaScript Object No…

如何用R语言在机器学习中建立集成模型?

介绍 在本文中,我将向您介绍集成建模的基础知识。 另外,为了向您提供有关集成建模的实践经验,我们将使用R进行集成。最近我们被客户要求撰写关于集成模型的研究报告,包括一些图形和统计输出。 1.什么是集成? 通常&am…