线程Thread
文章目录
- 一、概念
- 1、进程
- 2、线程
- 3、CPU与线程的关系
- 4、并行、并发
- 5、线程的生命周期
- 二、创建
- 1、继承Thread
- 2、实现Runnable接口
- 3、实现Callable接口
- 三、API
- 1、获取运行使用的线程
- 2、唯一标识
- 3、线程名
- 4、优先级
- 5、是否处于活动状态
- 6、守护线程
- 7、join
- 1、API
- 2、有无join对比
- 8、yield
- 9、sleep
- 10、线程中断
一、概念
1、进程
- 进程就是正在运行中的程序
2、线程
- 是1个进程(程序内部)的1条执行路径
- 单线程:1个进程中只有1个线程(1条执行路径)
- 多线程:1个进程中包含多个线程(多条执行路径)
- 线程之间堆内存、方法区内存共享;但是栈内存独立,1个线程一个栈
3、CPU与线程的关系
- 单核CPU:不能够做到真正的多线程并发,因为在一个时间单元内,只能执行一个线程的任务,多个线程谁获取时间片运行谁,每个线程获取时间片的概率相等,可能:t1、t2、t2、t2;给人一种多线程并发的感觉:其实是由于CPU的处理速度极快,多个线程之间频繁切换执行,跟人来的感觉是多个事情同时在做
4、并行、并发
- 并行:多核CPU同时执行多个任务。比如:多个人同时做不同的事
- 并发:单核CPU同时执行多个任务。比如:多个人做同一件事
5、线程的生命周期
- 新建状态
- 新建了线程对象,还没调用start方法
- 就绪状态
- 线程调用了start方法等待获取CPU时间片
- 表示当前线程具有抢夺CPU时间片的权力
- 运行状态
- 线程对象开始执行run方法
- run方法的开始执行标志着这个线程进入运行状态,当之前占有的CPU时间片用完之后,会重新回到就绪状态继续抢夺CPU时间片,当再次抢到CPU时间之后,会重新进入run方法接着上一次的代码继续往下执行
- 阻塞状态
- 当一个线程遇到阻塞事件,例如:sleep方法、获取synchronized排他锁失败(因为锁被其它线程所占用)等,此时线程会进入阻塞状态,阻塞状态的线程会放弃之前占有的CPU时间片,之前的时间片没了需要再次回到就绪状态抢夺CPU时间片
- 死亡状态
- run方法执行完毕或者因异常退出了run方法,该线程生命周期结束
二、创建
1、继承Thread
class Thread implements Runnable- 缺点:
- 由于java是单继承的,这导致继承了Thread后就不能在继承其它类了;在实际开发中会经常继承某个超类来复用其中的方法,这导致两者不能同时继承
- 继承线程后重写run方法来定义任务,这又导致我们将任务直接定义在线程上使得线程只能做该任务,无法并发执行其他任务,重用性变差
public class HandleMsg extends Thread{/** 线程标识 */private String threadKey;/** 构造方法用来区分不同线程便于测试 */public HandleMsg(String threadKey){this.threadKey=threadKey;}@Overridepublic void run(){for(int i=0;i<10;i++){System.err.println(threadKey+":run");}}}//匿名内部类lambda
Thread t1=new Thread(()->{for(int i=0;i<10;i++) {System.err.println("t1:run");}
};//创建2个线程对象
HandleMsg h1=new HandleMsg("h1");
HandleMsg h2=new HandleMsg("h2");//启动线程,开始执行实现的run方法
h1.start();
h2.start();
2、实现Runnable接口
- 优点:线程和线程执行的任务分离
public class HandleMsg implements Runnable{/** 线程标识 */private String threadKey;/** 构造方法用来区分不同线程便于测试 */public HandleMsg(String threadKey){this.threadKey=threadKey;}@Overridepublic void run(){for(int i=0;i<10;i++){System.err.println(threadKey+":run");}}}//创建2个任务对象
HandleMsg h1=new HandleMsg("h1");
HandleMsg h2=new HandleMsg("h2");//将任务1交给线程1
Thread t1=new Thread(h1);
//将任务2交给线程2
Thread t2=new Thread(h2);//启动线程,开始执行任务的run方法
t1.start();
t2.start();
3、实现Callable接口
FutureTask implements RunnableFuture,RunnableFuture<V> extends Runnable- 优点
- 线程和线程执行的任务分离
- 有返回值
- 可以声明抛出的异常
//Callable的泛型就是重写的call方法的返回值类型
public class HandleMsg implements Callable<String>{/** 线程标识 */private String threadKey;/** 构造方法用来区分不同线程便于测试 */public HandleMsg(String threadKey){this.threadKey=threadKey;}@Overridepublic String call() throws Exception{for(int i=0;i<10;i++){System.err.println(threadKey+":run");}return threadKey;}}//创建2个任务对象
HandleMsg h1=new HandleMsg("h1");
HandleMsg h2=new HandleMsg("h2");//创建FutureTask类包装任务对象,泛型就是任务类实现Callable的泛型,也就是call方法返回值的类型
FutureTask<String> f1=new FutureTask<>(h1);
FutureTask<String> f2=new FutureTask<>(h2);//将FutureTask对象交给线程
Thread t1=new Thread(f1);
Thread t2=new Thread(f2);//启动线程,开始执行任务的run方法
t1.start();
t2.start();//获取返回值
String result1=f1.get();
String result2=f2.get();
三、API
1、获取运行使用的线程
//在哪个方法执行就获取执行该方法的线程
Thread thread=Thread.currentThread();
2、唯一标识
long getId();
3、线程名
String getName();//线程启动之前可以设置线程名
void setName(String name);
4、优先级
- 线程有10个优先级,用1-10表示,默认为5
int getPriority();//启动之前设置
//线程无法主动获取cpu时间片,唯一可以干涉线程调度工作的方式就是修改线程的优先级,最大程度的改善获取cpu时间片的几率,理论上,线程优先级越高的线程获取cpu时间片的次数越多
void setPriority(int newPriority);
5、是否处于活动状态
boolean isAlive();
6、守护线程
- 守护线程又称为后台线程,默认创建出来的线程都是普通线程或称为前台线程
- 当进程结束时,所有正在运行的守护线程都会被强制中断
- 进程的结束:当一个进程中没有任何前台线程时即结束
- main主线程就是前台线程,不受其他线程影响,分配其他线程后接着干自己的事,其他线程执行的时候,main线程可能已经结束了
//是否为守护线程
boolean isDaemon();//启动之前设置
void setDaemon(boolean on);
7、join
- 作用是:让当前执行的线程陷入等待(内部调用了wait方法)。
- 永久等待:其实现原理是不停的检查当前线程是否存活,该线程的任务执行完毕后就会处于死亡状态,如果存活则说明任务还未执行完毕-继续等待
- 线程启动之后调用
1、API
//等待线程执行完任务后再往下执行,join(0);
void join();//等待线程执行一段时间后再往下执行,无论线程任务是否执行完毕,单位:毫秒
void join(long millis);
2、有无join对比
//1、程序正常运行顺序是不会等待线程任务执行完毕,就会往下执行
Thread t1=new Thread(()->{for(int i=0;i<5;i++){System.err.println(i);}
});
t1.start();System.err.println("next task");// 输出结果
// next task
// 0
// 1
// 2
// 3
// 4//2、调用join
Thread t1=new Thread(()->{for(int i=0;i<5;i++){System.err.println(i);}
});
t1.start();t1.join();System.err.println("next task");// 0
// 1
// 2
// 3
// 4
// next task
8、yield
- 线程让步
- 暂停(不是终止)当前正在执行的线程任务,让其它具有相同优先级或更高优先级的等待的线程执行任务(其它也会包含暂停的线程,所以有可能刚暂停就执行)
- 暂停的线程状态变化:运行状态 -> 就绪状态
- 暂停期间不会释放锁,所以其他线程获取不到锁
9、sleep
- 使线程睡眠
- sleep的睡眠期间不会释放锁,所以其它线程获取不到锁
- 睡眠线程的状态变化:运行状态 -> 阻塞状态 -> 就绪状态
//Thread的静态方法,单位:毫秒
static void sleep(long millis) throws InterruptedException;
- sleep和wait的区别
| sleep | wait |
|---|---|
| 属于Thread类 | 属于Object类 |
| 可以在任何地方使用 | wait、notify、notifyAll 只能在同步方法、同步控制块里面使用 |
| 睡眠期间不会释放锁 | 会释放锁,而且会将当前线程加入到等待队列中 |
| 不需要唤醒 | 可以被notify、notifyAll唤醒 |
10、线程中断
- 只是打断线程的睡眠,不会终止线程的继续执行
//线程是否中断
boolean isInterrupted();//中断线程睡眠
Thread t1=new Thread(()->{System.err.println("run......");try{//睡眠10sThread.sleep(10000L);}catch(InterruptedException e){e.printStackTrace();}System.err.println("end......");
});//启动线程
t1.start();//中断睡眠
//线程不会睡眠10s,而是被中断,抛出InterruptedException,捕获该异常后,继续执行后续的代码
t1.interrupt();System.err.println("next task");// 执行结果
// next task
// run......
// end......
相关文章:
线程Thread
文章目录 一、概念1、进程2、线程3、CPU与线程的关系4、并行、并发5、线程的生命周期 二、创建1、继承Thread2、实现Runnable接口3、实现Callable接口 三、API1、获取运行使用的线程2、唯一标识3、线程名4、优先级5、是否处于活动状态6、守护线程7、join1、API2、有无join对比 …...
如何使用CSS实现一个渐变背景效果?
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 使用CSS实现渐变背景效果⭐ 线性渐变(Linear Gradient)⭐ 径向渐变(Radial Gradient)⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订…...
初始C语言(7)——详细讲解有关初阶指针的内容
系列文章目录 第一章 “C“浒传——初识C语言(1)(更适合初学者体质哦!) 第二章 初始C语言(2)——详细认识分支语句和循环语句以及他们的易错点 第三章 初阶C语言(3)——…...
ArcGIS Pro技术应用(暨基础入门、制图、空间分析、影像分析、三维建模、空间统计分析与建模、python融合、案例应用)
GIS是利用电子计算机及其外部设备,采集、存储、分析和描述整个或部分地球表面与空间信息系统。简单地讲,它是在一定的地域内,将地理空间信息和 一些与该地域地理信息相关的属性信息结合起来,达到对地理和属性信息的综合管理。GIS的…...
RISC-V公测平台发布 · 数据库在RISC-V服务器上的适配评估
前言 上一期讲到YCSB在RISC-V服务器上对MySQL进行性能测试(RISC-V公测平台发布 使用YCSB测试SG2042上的MySQL性能),在这一期文章中,我们继续深入讨论RISC-V数据库的应用。本期就继续利用HS-2平台来测试数据库软件在RISC-V服务器…...
UE5.2 LyraDemo源码阅读笔记(五)输入系统
Lyra里使用了增强输入系统,首先知道增强输入系统里的三个类型配置。 一、Input Actions (IA): 输入操作带来的变量,与玩家的输入组件绑定,回调里驱动玩家行为。 二、InputMappingContext(IMC):…...
线段树详解——影子宽度
OK,今天来讲一讲线段树~~ 线段树是什么线段树的实现线段树的时间复杂度线段树的应用线段树的节点结构其他操作和优化例题——影子宽度输入输出格式输入格式输出格式 输入输出样例输入样例输出样例 例题讲解 线段树是什么 线段树( S e g m e n t Segmen…...
使用R语言绘制折线图
写在前面 昨天我们分享了使用Python绘制折线图的教程,跟着NC学作图 | 使用python绘制折线图,考虑到很多同学基本不使用Python绘图。那么,我们也使用R语言复现此图形。 此外,在前期的教程中,我们基本没有分享过折线图的教程。因此,我们在这里也制作一期关于折线图的教程。…...
无涯教程-Perl - wantarray函数
描述 如果当前正在执行的函数的context正在寻找列表值,则此函数返回true。在标量context中返回false。 语法 以下是此函数的简单语法- wantarray返回值 如果没有context,则此函数返回undef;如果lvalue需要标量,则该函数返回0。 例 以下是显示其基本用法的示例…...
【gitkraken】gitkraken自动更新问题
GitKraken 会自动升级!一旦自动升级,你的 GitKraken 自然就不再是最后一个免费版 6.5.1 了。 在安装 GitKraken 之后,在你的安装目录(C:\Users\<用户名>\AppData\Local\gitkraken)下会有一个名为 Update.exe 的…...
《Java Web程序设计》试卷03
《Java Web程序设计》试卷03 课程编码: 301209 适用专业: 计算机应用(包括JAVA方向) 注 意 事 项 1、首先按要求在试卷标封处填写你所在的系(部)、专业、班级及学号和姓名; 2、仔细阅读各类题目的回答要求,…...
怎么查看小程序中的会员信息
商家通过查看会员信息,可以更好地了解用户,并为他们提供更个性化的服务和推荐。接下来,就将介绍如何查看会员信息。 商家在管理员后台->会员管理处,可以查看到会员列表。支持搜索会员的卡号、手机号和等级。还支持批量删除会员…...
网络安全—黑客—自学笔记
想自学网络安全(黑客技术)首先你得了解什么是网络安全!什么是黑客! 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全…...
深度解读波卡 2.0:多核、更有韧性、以应用为中心
本文基于 Polkadot 生态研究院整理,有所删节 随着波卡 1.0 的正式实现,波卡于 6 月 28 日至 29 日在哥本哈根举办了年度最重要的会议 Polkadot Decoded 2023,吸引了来自全球的行业专家、开发者和爱好者,共同探讨和分享波卡生态的…...
微服务中间件--Eureka注册中心
Eureka注册中心 a.eureka原理分析b.搭建eureka服务c.服务注册d.服务发现 a.eureka原理分析 1.每个服务启动时,将自动在eureka中注册服务信息 (每个服务每隔30秒发送一次的心跳续约,当某个服务没有发送时,eurekaServer将自动剔除该服务&#x…...
积跬步至千里 || 矩阵可视化
矩阵可视化 矩阵可以很方面地展示事物两两之间的关系,这种关系可以通过矩阵可视化的方式进行简单监控。 定义一个通用类 from matplotlib import pyplot as plt import seaborn as sns import numpy as np import pandas as pdclass matrix_monitor():def __init…...
zookeeper详细介绍
ZooKeeper是一个开源的分布式协调服务,具有以下一些关键特点: 数据模型 ZooKeeper的数据模型采用层次化的多叉树形结构,每个节点称为znode,类似于文件系统中的文件和目录。每个znode可以存储数据和控制信息。一致性保证 ZooKeeper通过ZAB协议,实现分布式环境下数据的强一致性,…...
面板市场趋势分析:价格上涨势头或将减缓 | 百能云芯
8月末,面板价格报价公布,市场研究机构TrendForce指出,电视面板今年以来已经上涨超过30%,虽然下游品牌商对于价格上涨提出了不同声音,但由于面板厂商采取了按需生产的策略,8月仍然出现了3~5%的价格上涨。Tre…...
JVM性能调优
java 如何跨平台,如何一次编译到处执行 是由于java在不同的jvm上编译,jvm在软件层面屏蔽不同操作系统在底层硬件与指令上的区别。 jvm 包括 new 的对象都是放在堆中 栈,给线程单独使用(线程私有),存储一个…...
【全链路追踪】XXL-JOB添加TraceID
文章目录 一、背景调用路径部署环境问题 二、方案三、Demo示例1、MDC2、RequestInterceptor3、HandlerInterceptor4、logback.xml 四、后续改进思路 一、背景 首先这个项目属于小型项目,由于人手以及时间限制,并未引入Skywalking等中间件来做调用链路追…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...
git: early EOF
macOS报错: Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...
LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)
在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...
基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)
引言 在嵌入式系统中,用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例,介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单,执行相应操作,并提供平滑的滚动动画效果。 本文设计了一个…...
