多线程编程3——线程的状态

一、状态是线程的状态

状态是PCB中与调度相关的属性线程是CPU调度执行的基本单位。所以,状态是线程的属性谈到状态,考虑的都是线程的状态,不是进程!!!

二、在Java中,线程的状态有哪几种?

在Java中,线程的状态比操作系统内核中的更加详细, 线程的状态有以下六种:

状态说明
NEW创建了Thread对象,但没调用start(内核中还没有创建对应的PCB)
TERMINATED内核中的PCB已经执行完销毁了,Thread对象还在
RUNNABLE可运行的(正在CPU上执行的 和 在就绪队列中随时可以去CPU上执行 这两种统一都叫做RUNNABLE状态,不做区分,也区分不了)
WAITING阻塞(线程PCB正在阻塞队列中)
TIMED_WAITING阻塞(线程PCB正在阻塞队列中)
BLOCKED阻塞(线程PCB正在阻塞队列中)

对这六种状态,下面进行详细介绍:

1、首先, 主线任务是,NEW,RUNNABLE,TERMINATED

比如下面的代码(当run方法中没有sleep或其他会造成线程阻塞的代码时):

刚开始,创建了Thread对象,但还没执行到start方法,这时,线程的状态就是NEW。

接着,调用start创建线程,当线程参与调度,这时,线程的状态就是RUNNABLE。

接着,主线程调用join方法,阻塞等待线程执行结束,当线程执行完run方法,线程就结束了,PCB就释放了,但是 t对象还在,这时,线程的状态就是TERMINATED 

 对于TERMINATED这个状态,我再啰嗦几句:

这个状态是不得已而存在的,是为了把 PCB已经释放的 线程对象 标识成无效。

当线程结束,内核中的PCB就释放了,但因为Java中对象的生命周期自有其规则,和PCB的生命周期并非完全一致。所以PCB释放时,无法保证Java代码中的 t对象也释放了。 那么就一定会存在,内核中的PCB已经释放,但代码中 t对象还存在的这种情况。

所以我们就需要一个特定的状态把 t对象标识成无效,让程序员知道,该对象已经没用了

避免出现线程已经结束了,但由于t对象还在,误以为线程还存在,还使用该线程进行多线程编程的情况。这就比较难受了。

所以,TERMINATED这个状态必须得存在,没有办法。

当线程的状态是TERMINATED时,不能使用该线程进行多线程编程了但是,对象还在,所以我们可以调用对象中的方法和属性的,这并不冲突。

举例如下:(这些 对象的方法都可以调用,完全没问题)

2、线程在RNUUABLE状态下因为一些原因导致线程进入阻塞状态,即进入支线任务。当线程在执行run方法过程中,因为各种原因产生阻塞,这时,线程状态就会发生改变,就不会一直处于RUNNABLE状态了。

线程因为不同原因发生阻塞会进入不同的状态

(1)TIMED_WAITING:因为需要等待一定的时间产生的阻塞,sleep等类似方法时间到了,就从该状态中出来,回到RUNNABLE状态了

(2)WAITING:因为需要等待其他人来通知产生的阻塞,wait/join等方法条件满足,通知到了,就从该状态中出来,回到RUNNABLE状态了

(3)BLOCKED:因为等待锁产生的阻塞。获取到锁,就从该状态中出来,回到RUNNABLE状态了

下面我通过代码来演示一下TIMED_WAITING状态:

线程的run方法中有个循环,循环10万次,循环内部有个sleep,休眠10毫秒。当线程运行i<10_0000这样的代码时,线程的状态就是RUNNABLE;当处于sleep阻塞时,线程的状态就是TIMED_WAITING。

主线程的main方法中也有个循环,循环1千次,循环内部打印线程的状态。由于这个循环在start方法之后,所以打印的线程状态,要么是RUNNABLE(当线程在CPU上执行或在就绪队列中时),要么是TIMED_WAITING(当线程在阻塞等待时)。获取的状态是什么,取决于获取的那一瞬间,线程处于哪个状态(正在CPU上执行或在就绪队列中,还是在阻塞等待)。

但是为啥会先打印RUNNABLE,再打印TIMED_WAITING,且TIMED_WAITING打印的更多呢?

因为循环在start方法之后,如上图,在主线程打印线程的状态时,线程先是在CPU上执行i<10_0000这样的代码,然后才进入sleep等待。这样的过程会循环10_0000次。所以,当主线程循环打印1000次线程的状态时,先打印的状态是RUNNABLE,后打印的状态是TIMED_WAITING。因为sleep休眠10毫秒,虽然10ms对人来说很快,但对计算机来说还是很慢的。而线程在CPU上执行的代码却很少。线程在CPU上执行的时间远远小于线程sleep的时间,所以打印的TIMED_WAITING状态更多(进入sleep产生的阻塞就是TIMED_WAITING状态)。

三、多线程的意义到底是啥?

多线程最核心的地方:抢占式执行,随机调度

使用多线程编程能解决“并发编程”的问题,更好的利用了CPU的多核资源,提高执行速度。

下面我通过一个例子,让大家感受一下,单个线程和多个线程之间,执行速度的差别。

程序主要分成:CPU密集 和 IO密集 两种。CPU密集:包含了大量的加减乘除等算术运算。IO密集:涉及到读写文件,读写控制台,读写网络。

我们举一个CPU密集的例子,比如现在有一个运算量很大的任务,看一下单线程和多线程的区别。

假设当前有两个变量,需要把两个变量各自自增 100亿 次。 

单线程(只有主线程):先对 a自增,再对 b自增。

两个线程(主线程和线程):线程先对 a自增,再对 b自增。

三个线程(主线程,线程1,线程2):线程1 和 线程2 分别对 a和b 自增。

加个计时的操作来衡量代码的执行速度,System.currentTimeMillis() —— 获取到当前系统的 ms级时间戳。 

 

上述代码是一个线程完成的,只有主线程。

我们可以看到,执行时间大约是1万 ms 

 

 

上述代码是两个线程完成的,主线程 和 线程t。在主线程中调用start方法创建一个线程,这个线程负责先对 a自增,再对 b自增 。

我们可以看到,执行时间大约是 5000 ms

 

上述代码是三个线程完成的,主线程,线程t1 和 线程t2。线程t1 和 线程t2 分别对 a和b 自增。

我们可以看到,执行时间大约 3000 ms

刚开始,我将计时代码:long begin = System.currentTimeMillis();写在了两个start方法之后,发现结果有问题。  

为什么呢?为什么不能写在start后,要写在start前呢?

因为主线程,线程t1,线程t2 是并发执行的,CPU是随机调度的,哪个线程先去CPU上执行是随机的。如果把计时代码写在两个start 方法之后,在主线程还没执行到计时代码时,线程t1 或 线程t2 可能已经去执行run方法中的代码了。就不准了。总共的执行时间会被少算。

通过上面三个代码,观察发现:

只有主线程:10000 ms 

主线程,线程t:5000 ms

主线程,线程t1,线程t2:3000 ms

总结:多线程能充分利用CPU的多核资源,提高运行效率。 

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

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

相关文章

作业车间调度问题:P还是NP

获取更多资讯&#xff0c;赶快关注上面的公众号吧&#xff01; 文章目录 基本概念多项式时间指数时间 P问题&#xff08;多项式问题&#xff09;NP问题&#xff08;非确定性多项式问题&#xff09;暴力穷举法动态规划 P与NP关系&#xff1a;作业车间调度问题是典型的NP难问题 …

将vite项目(vue/react)使用vite-plugin-pwa配置为pwa应用,只需要3分钟即可

将项目配置为pwa模式&#xff0c;就可以在浏览器里面看到安装应用的选项&#xff0c;并且可以将web网页像app一样添加到手机桌面或者pad桌面上&#xff0c;或者是电脑桌面上&#xff0c;这样带来的体验就像真的在一个app上运行一样。为了实现这个目的&#xff0c;我们可以为vue…

vue3-hand-mobile

当我写完手势移动事件后&#xff0c;我又通过svg的方法添加了一段文字和polygon。当我在这个蓝色的polygon上滑动手势的时候&#xff0c;会报错。 可能这个bug只是我个人的代码导致的。但是我觉得vue3-hand-mobile插件的这一段代码写的有问题。 我通过circular-json库修复了这…

vite+vue3+ts项目上线docker 配置反向代理API

这次重点的坑是反向代理。 1。项目中配置代理&#xff0c;为了跨域请求数据 项目根目录中新建vite.config.ts文件 在文件中添加配置代理 注意&#xff1a;其中 /api 和target 的地址后面没有 / 2。在项目根目录中新建Httprequest.ts文件&#xff0c;引入axios&#xff0c;并…

网诺安全文件上传总结

一、文件上传简介 文件上传漏洞是指用户上传了一个可执行的脚本文件&#xff08;木马、病毒、恶意脚本、webshell等&#xff09;&#xff0c;并通过此脚本文件获得了执行服务器端命令的能力。上传点一般出现在头像、导入数据、上传压缩包等地方&#xff0c;由于程序对用户上传…

VUE使用computed实现子父组件双向绑定数据

上面字符串文字是父级的数据&#xff0c;下面表单是父级传给子组件并实现双向绑定 // 这里是vue3写法&#xff0c;vue2 同样在computed里写 get(){} 即可 const form computed({get(){ // props.modelForm 就是父级传过来的对象const proxy new Proxy(props.modelForm,{get(t…

网络原理——传输层2

1.TCP协议 TCP协议是工作中最常用到的协议。 TCP协议格式&#xff1a; 源端口号&#xff08;16位&#xff09;&#xff1a;源端口标识发送方的应用程序。目的端口号&#xff08;16位&#xff09;&#xff1a;目的端口标识接收方的应用程序。序列号&#xff08;32位&#xf…

echarts 堆叠柱状图数据差值较大,导致显示图形差异很大

问题描述&#xff1a; echarts 堆叠柱状图数据差值较大&#xff0c;导致显示图形差异很大 如图&#xff1a; 解决方案 柱状图、折线图 给 y轴或者x轴type设置log 就可以 。饼图 设置 minAngle

kafka summary

最近整体梳理之前用到的一些东西&#xff0c;回顾Kafka的时候好多东西都忘记了&#xff0c;把一些自己记的比较模糊并且感觉有用的东西整理一遍并且记忆一遍&#xff0c;仅用于记录以备后续回顾 Kafka的哪些场景中使用了零拷贝 生产者发送消息&#xff1a;在 Kafka 生产者发送…

使用.NET6 Avalonia开发跨平台三维应用

本文介绍在Vistual Studio 2022中使用Avalonia和集成AnyCAD Rapid AvaloniaUI三维控件的过程。 0 初始化环境 安装Avalonia.Templates dotnet new install Avalonia.Templates若之前安装过可忽略此步骤。 1 创建项目 选择创建AvaloniaUI项目 选一下.NET6版本和Avalonia版…

RX-8564 LC实时时钟模块

.内置 32.768 kHz 晶体单元(频率精度调整完毕) .接口类型&#xff1a;I2C-Bus 接口 (400 kHz) .工作电压范围&#xff1a;1.8 V ~ 5.5 V .计时&#xff08;保持&#xff09;电压范围 &#xff1a;1.0 V ~ 5.5 V / -20 ˚C ~70 ˚C .低待机电流 &#xff1a;275 nA / 3.0…

基于BiLSTM-CRF对清华语料文本进行分类

安装TorchCRF !pip install TorchCRF1.0.6 构建BiLSTM-CRF # encoding:utf-8import torch import torch.nn as nn from TorchCRF import CRFfrom torch.utils.data import Dataset from sklearn.model_selection import train_test_split import numpy as npimport torch im…

python-自动化篇-运维-语音识别

文章目录 理论文本转换为语音使用 pyttsx使用 SAPI使用 SpeechLib 语音转换为文本 代码和效果01使用pyttsx实现文本_语音02使用SAPI实现文本_语音03使用SpeechLib实现文本_语音04使用PocketSphinx实现语音转换文本 理论 语音识别技术&#xff0c;也被称为自动语音识别&#xf…

Threejs 展示——点击模型指定部分添加高亮显示

文章目录 需求分析需求 如下图所示,点击模型指定部分添加高亮显示 分析 绘制一个 canvas将该 canvas 将渲染器挂载到dom<template><canvas id="three" /> </template><scr

基于C#制作一个俄罗斯方块小游戏

目录 引言游戏背景介绍游戏规则游戏设计与实现开发环境与工具游戏界面设计游戏逻辑实现游戏优化和测试性能优化测试工具和流程说明引言 俄罗斯方块是一款经典的益智游戏,深受玩家喜爱。本文将介绍如何使用C#编程语言制作一个简单的俄罗斯方块小游戏,并探讨其设计与实现过程。…

从公有云对象存储迁移到回私有化 MinIO需要了解的所有信息

我们上一篇文章《如何从 AWS S3 遣返到 MinIO》的反响非常出色 - 我们已经接到了数十个企业的电话&#xff0c;要求我们提供遣返建议。我们已将这些回复汇总到这篇新文章中&#xff0c;其中我们更深入地研究了与遣返相关的成本和节省&#xff0c;以便您更轻松地进行自己的分析。…

递归、分治

递归 Recursion 函数自身调用自身通过函数体来进行的循环以自相似的方法重复进行的过程递归的三个关键 定义需要递归的问题&#xff08;重叠子问题&#xff09;- 数学归纳法思维确定递归边界保护与还原现场 递归形式时间复杂度规模问题举例指数型 2 n 2^n 2n子集排列型 n ! …

基于BERT模型实现文本相似度计算

配置所需的包 !pip install transformers2.10.0 -i https://pypi.tuna.tsinghua.edu.cn/simple !pip install HanziConv -i https://pypi.tuna.tsinghua.edu.cn/simple 数据预处理 # -*- coding: utf-8 -*-from torch.utils.data import Dataset from hanziconv import Han…

统计学-R语言-7.3

文章目录 前言总体方差的检验一个总体方差的检验两个总体方差比的检验 非参数检验总体分布的检验正态性检验的图示法Shapiro-Wilk和K-S正态性检验总体位置参数的检验 练习 前言 本篇文章继续对总体方差的检验进行介绍。 总体方差的检验 一个总体方差的检验 在生产和生活的许多…

Hypermesh中模型抽取中面的方法

一、自动抽取中面 二、手动抽取中面 offsetplanessweeps会记录所抽取的中面由哪两个面形成的 planes&#xff1a;所识别的对面是两个平面&#xff0c;就会在两平面中间区域插入一个中面 sweeps&#xff1a;所识别的对面是两个曲面时&#xff0c;就会在两个曲面中间区域插入一个…