并发编程的故事——Java线程
Java线程
`
文章目录
- Java线程
- 一、线程创建
- 二、线程运行
- 三、线程运行
- 四、主线程和守护线程
- 五、线程的五种状态
- 六、线程的六种状态
- 七、烧水泡茶案例
一、线程创建
创建线程方法一:
Thread重写run方法
@Slf4j(topic = "c.MyTest1")
public class MyTest1 {public static void main(String[] args) {Thread t=new Thread(){@Overridepublic void run() {log.info("好人");}};t.setName("线程1");t.start();log.info("main测试");}
}创建方法2:
直接写一个Runable传给线程Thread
@Slf4j(topic = "c.Test2")
public class Test2 {public static void main(String[] args) {Runnable r = () -> {log.debug("running");};Thread t = new Thread(r, "t2");t.start();}
}
Thread和Runable的区别
Thread实现了Runable方法,也就是说Thread可以覆盖Runable的任务方法执行run。但是也可以通过传入任务来执行对应的Runable方法(如下面代码所示)。
@Overridepublic void run() {if (target != null) {target.run();}
}
创建方法3:
FutureTask实现了Runnable和Future,Future主要是用来返回值的。其实相当于也是一个任务类但是需要实现Callable实现类对象传入到task上。并且执行之后才能够使用task的get来获取数据,如果没有执行线程那么get就会阻塞
@Slf4j(topic = "c.MyTest2")
public class MyTest2 {public static void main(String[] args) throws ExecutionException, InterruptedException {FutureTask<Integer> task=new FutureTask<Integer>(new Callable<Integer>() {@Overridepublic Integer call() throws Exception {log.debug("你好");return 4;}});Thread t=new Thread(task,"t1");t.start();log.debug("{}",task.get());}
}
总结:更推荐方法2,原因是Runable就是任务,把任务和线程分开才能更好的分配任务。
二、线程运行
命令
jps:查看java进程
tasklist:windos查看所有进程
taskkill /F /PID XXX:杀死某个进程
三、线程运行
线程的栈
每次开启一个线程都会产生一个线程的栈给线程使用,实际上就是一开始分配的虚拟机栈。
每个栈都有多个栈帧
线程只能有一个活动栈帧
线程执行的过程
先分配栈给线程,线程调用main方法,在栈分配一个栈帧给main方法,栈帧保存锁记录、局部变量表、操作数栈、返回地址(返回到原来的栈帧方法的下一条指令)

线程上下文切换
导致上下文切换的条件:
时间片用完
优先级
垃圾回收
自己调用sleep、wait等
线程的状态包括:
程序计数器,记录执行到什么位置
虚拟机栈,包括所有栈帧信息
常见方法
start
线程进入就绪状态,等待调度器调用。这里相当于是开启了一个新的线程
run
执行Runnable里面的方法。这里并没有开启线程,只是通过本线程执行代码
如果开启了两次start就会出现线程状态异常的问题IlegalThreadStateException
线程的两个状态
NEW
start之后就是Runnable等待调度
sleep
线程睡眠,并把状态改为Timed Waiting,被打断的时候会抛出异常InterruptedException。可以通过TimeUnit.SECONDS.sleep来规定睡眠时间的单位。睡眠可以使用在while循环自转的地方,如果长时间自转就会消耗CPU的使用时间,其他线程无法使用
interrupt
唤醒线程,如果线程处于睡眠状态那么就会抛出异常
public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread("t1") {@Overridepublic void run() {log.debug("enter sleep...");try {Thread.sleep(2000);} catch (InterruptedException e) {log.debug("wake up...");e.printStackTrace();}}};t1.start();Thread.sleep(1000);log.debug("interrupt...");t1.interrupt();}
yield
其实就是把线程状态从Running转变到Runnable暂时让出cpu,重新去竞争
setPriority
设置优先级是给调度器进行提示,先执行这个线程,但是仍然没有办法控制线程。
join
join实际上就是卡点,就是一定要等待调用join的线程完成后才能执行下面的代码
@Slf4j(topic = "c.Test10")
public class Test10 {static int r = 0;public static void main(String[] args) throws InterruptedException {test1();}private static void test1() throws InterruptedException {log.debug("开始");Thread t1 = new Thread(() -> {log.debug("开始");sleep(1);log.debug("结束");r = 10;},"t1");t1.start();t1.join();log.debug("结果为:{}", r);log.debug("结束");}
}
同步应用案例
多线程的join只需要等待最长的那个线程就可以了,因为它们是并行执行的。
test3案例,实际上就是限时等待,如果超过时间那么就不等了。如果没有超过时间,那么结束join还是以处理完线程的任务时间为主,而不是最大的等待时间

@Slf4j(topic = "c.TestJoin")
public class TestJoin {static int r = 0;static int r1 = 0;static int r2 = 0;public static void main(String[] args) throws InterruptedException {test2();}public static void test3() throws InterruptedException {Thread t1 = new Thread(() -> {sleep(2);r1 = 10;});long start = System.currentTimeMillis();t1.start();// 线程执行结束会导致 join 结束log.debug("join begin");t1.join(3000);long end = System.currentTimeMillis();log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start);}private static void test2() throws InterruptedException {Thread t1 = new Thread(() -> {sleep(1);r1 = 10;});Thread t2 = new Thread(() -> {sleep(2);r2 = 20;});t1.start();t2.start();long start = System.currentTimeMillis();log.debug("join begin");t1.join();log.debug("t1 join end");t2.join();log.debug("t2 join end");long end = System.currentTimeMillis();log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start);}private static void test1() throws InterruptedException {log.debug("开始");Thread t1 = new Thread(() -> {log.debug("开始");sleep(1);log.debug("结束");r = 10;});t1.start();t1.join();log.debug("结果为:{}", r);log.debug("结束");}
}

interrupt
打断阻塞
打断sleep和wait。打断后会抛出异常到那时不会给它打上打断标记。而且这里需要给主线程睡眠一会,不然t1线程还没睡眠,主线程就已经调用打断,那么这个时候的打断是打断t1,并且加上打断标记,但是打断睡眠并不会有打断标记
@Slf4j(topic = "c.Test11")
public class Test11 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {log.debug("sleep...");try {Thread.sleep(5000); // wait, join} catch (InterruptedException e) {e.printStackTrace();}},"t1");t1.start();Thread.sleep(1000);log.debug("interrupt");t1.interrupt();log.debug("打断标记:{}", t1.isInterrupted());}
}
打断正常
当我们打断的事正常的线程(没在sleep或wait),那么就会给这个线程加上打断标记。但是要不要打断取决于被打断线程的意愿,其它线程只能给一个通知。
@Slf4j(topic = "c.Test12")
public class Test12 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while(true) {boolean interrupted = Thread.currentThread().isInterrupted();if(interrupted){break;}}}, "t1");t1.start();Thread.sleep(1000);log.debug("interrupt");t1.interrupt();}
}
LockSupport
其实就是一个锁的支持类,它的park方法可以模拟sleep把线程进行阻塞,但是需要标记是false的时候。如果打断标记是true那么就无法使用。但是这个地方可以使用Thread.interrupted来获取打断标记状态和消除标记。
public static void test5() {Thread t1 = new Thread(()->{log.debug("park...");LockSupport.park();log.debug("unpark...");log.debug("打断状态:{}", Thread.interrupted());LockSupport.park();log.debug("unpark...");},"t1");t1.start();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}t1.interrupt();}
四、主线程和守护线程
守护线程其实就是Daemon。也就是在其它非守护线程运行完之后,无论守护线程是否还有任务需要执行都会强制停止。
垃圾回收器是守护线程
tomcat的Acceptor和poller
@Slf4j(topic = "c.Test15")
public class Test15 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (true) {if (Thread.currentThread().isInterrupted()) {break;}}log.debug("结束");}, "t1");t1.setDaemon(true);t1.start();Thread.sleep(1000);log.debug("结束");}
}
五、线程的五种状态
1、初始:new线程的时候
2、可运行:执行了start
3、运行:线程可以使用cpu的时候
4、阻塞:不能被cpu调度器使用的时候
5、终止:线程结束的时候

六、线程的六种状态
NEW:初始化
RUNNABLE:包括了运行、可运行和阻塞,通常表示正在运行
WAITING:没有时间限制的等待
TIMED_WAITING:有时间限制的等待
BLOCKED:阻塞
TERMINATED:终止
七、烧水泡茶案例
join思路
其实就是老王洗烧壶和烧水,小王洗茶壶、茶杯、茶叶,等待烧水完成之后泡茶。可以用join来等待t1处理。
Slf4j(topic = "c.Test16")
public class Test16 {public static void main(String[] args) {Thread t1 = new Thread(() -> {log.debug("洗茶壶");Sleeper.sleep(1);log.debug("烧水");Sleeper.sleep(5);}, "老王");Thread t2=new Thread(()->{log.debug("洗茶壶");Sleeper.sleep(1);log.debug("洗茶叶");Sleeper.sleep(2);log.debug("洗茶杯");Sleeper.sleep(1);try {t1.join();} catch (InterruptedException e) {e.printStackTrace();}log.debug("泡茶");},"小王");t1.start();t2.start();}
}
相关文章:
并发编程的故事——Java线程
Java线程 文章目录 Java线程一、线程创建二、线程运行三、线程运行四、主线程和守护线程五、线程的五种状态六、线程的六种状态七、烧水泡茶案例 一、线程创建 创建线程方法一: Thread重写run方法 Slf4j(topic "c.MyTest1") public class MyTest1 {publ…...
菜鸟教程《Python 3 教程》笔记(13):迭代器与生成器
菜鸟教程《Python 3 教程》笔记(13) 13 迭代器与生成器13.1 迭代器13.1.1 创建一个迭代器13.1.2 StopIteration 13.2 生成器13.3 yield 使用浅析13.3.1 通过 iterable 对象来迭代13.3.2 使用 isgeneratorfunction 判断13.3.3 类的定义和类的实例13.3.4 r…...
ceph架构及 IO流程
CEPH是由多个节点构成的集群,它具有良好的可扩展性和可靠性。节点之间相互通信以达到: 存储和检索数据 数据复制 监控集群的健康状况 保证数据的完整性 检测故障并恢复 基本架构如下图: 分布式对象存储系统RADOS是CEPH最为关键的技术&a…...
ssh 基本用法与免密登录
基本用法 远程连接服务器: ssh userhostname user:用户名hostname:IP地址或域名 举个例子,假设我们的user是tom,hostname是123.45.67.890 可以输入:ssh tom123.45.67.890 第一次登陆时会提示:…...
Unity3D 如何在ECS架构下,用Unity引擎进行游戏开发详解
前言 Unity3D是一款强大的游戏引擎,它提供了丰富的功能和工具,可以帮助开发者快速构建高质量的游戏。而Entity Component System(ECS)是Unity3D中一种新的架构模式,它可以提高游戏的性能和可扩展性。本文将详细介绍在…...
Kotlin协程flow的debounce与管道Channel
Kotlin协程flow的debounce与管道Channel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.delay import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import kotlinx.coroutines.runBlockingco…...
在JavaScript中,你可以使用多种方法来查找包含特定元素的数组或对象
1、indexOf():这个方法返回元素在数组中首次出现的位置。如果没有找到元素,则返回-1。 let array [1, 2, 3, 4, 5]; console.log(array.indexOf(3)); // 输出: 2 console.log(array.indexOf(6)); // 输出: -12、includes():这个方法检查数…...
实力认证!OceanBase获“鼎信杯”优秀技术支撑奖
6 月 30 日,2023 “鼎信杯”信息技术发展论坛在京隆重举办第二届“鼎信杯”大赛颁奖典礼。OceanBase 凭借完全自主研发的原生分布式数据库,以及丰富的核心系统国产数据库升级案例,斩获“优秀技术支撑奖”。 论坛上,国内首个基于在…...
分布式锁实现一. 利用Mysql数据库update锁
文章目录 分布式锁1、什么是分布式锁:2、分布式锁应该具备哪些条件: 基于数据库的分布式锁代码传送代码运行 分布式锁 1、什么是分布式锁: 分布式锁,即分布式系统中的锁。在单体应用中我们通过锁解决的是控制共享资源访问的问题…...
第一百三十一回 如何使用MethodChannel
文章目录 知识回顾示例代码经验总结我们在上一章回中介绍了通道相关的内容,本章回中将介绍其中的一种通道:MethodChannnel.闲话休提,让我们一起Talk Flutter吧。 知识回顾 我们在上一章回中介绍了通道的概念和作用,并且提到了通道有不同的类型,本章回将其中一种通道:Me…...
贝锐蒲公英异地组网方案,如何阻断网络安全威胁?
随着混合云和移动办公的普及,企业网络面临着越来越复杂的安全威胁环境。 大型企业有足够的能力和预算,构建覆盖全部个性化需求的定制化网络安全方案。 但对于广大中小企业来说,由于实际业务发展情况,他们难以在部署周期、预算成本…...
CTFhub-文件上传-无验证
怎样判断一个网站是 php asp jsp 网站 首先,上传用哥斯拉生成 .php 文件 然后,用蚁剑测试连接 找到 flag_1043521020.php 文件,进去,即可发现 flag ctfhub{ee09842c786c113fb76c5542}...
Java“牵手”京东商品详情数据,京东API接口申请指南
京东平台商品详情接口是开放平台提供的一种API接口,通过调用API接口,开发者可以获取京东商品的标题、价格、库存、月销量、总销量、库存、详情描述、图片等详细信息 。 获取商品详情接口API是一种用于获取电商平台上商品详情数据的接口,通过…...
瓜分双十一10亿红包设计:在线分享教程?
在如今激烈的市场竞争中,瓜分红包营销活动成为了各大企业争相使用的一种营销手段。这种活动不仅能够吸引用户的关注和参与,还能够提高用户的粘性和忠诚度。那么,如何自建瓜分红包营销活动呢?下面将为大家详细解析。 首先ÿ…...
day 43 | ● 123.买卖股票的最佳时机III ● 188.买卖股票的最佳时机IV
123.买卖股票的最佳时机III func maxProfit(prices []int) int {dp : make([][]int , len(prices))dp[0] []int{0, -prices[0], 0, -prices[0], 0}for i : 1; i < len(prices);i{val0 : dp[i - 1][0]val1 : max(dp[i - 1][0] - prices[i], dp[i - 1][1])val2 : max(dp[i - …...
客路旅行(KLOOK)面试(部分)(未完全解析)
一面 用过Chatgpt的哪个版本,了解Chatgpt版本之间的差异吗 什么是优雅部署?newBing: 服务启动时,检查依赖的组件或容器是否就绪,如果不就绪,等待或重试,直到就绪后再注册到服务中心,对外提供服…...
时序预测 | MATLAB实现基于QPSO-BiGRU、PSO-BiGRU、BiGRU时间序列预测
时序预测 | MATLAB实现基于QPSO-BiGRU、PSO-BiGRU、BiGRU时间序列预测 目录 时序预测 | MATLAB实现基于QPSO-BiGRU、PSO-BiGRU、BiGRU时间序列预测效果一览基本描述程序设计参考资料 效果一览 基本描述 1.时序预测 | MATLAB实现基于QPSO-BiGRU、PSO-BiGRU、BiGRU时间序列预测&a…...
el-select码值枚举
当码值的数据是自己写的时候: 例如:isOrNo:[{label:是,value:1},{label:否,value:‘2’}], 当传给后端值时下拉选择是,值为1,我们当前拿到的只是值为value:1࿰…...
【多面体:知识蒸馏:Pansharpening】
Multipatch Progressive Pansharpening With Knowledge Distillation (基于知识蒸馏的多面体渐进锐化算法) 在这篇文章中,我们提出了一种新的多面体和多级泛锐化方法与知识蒸馏,称为PSDNet。不同于现有的pansharpening方法&…...
【python爬虫】4.爬虫实操(菜品爬取)
文章目录 前言项目:解密吴氏私厨分析过程代码实现(一)获取与解析提取最小父级标签一组菜名、URL、食材写循环,存列表 代码实现(二)复习总结 前言 上一关,我们学习了用BeautifulSoup库解析数据和…...
GooglePlay多账号管理神器推荐:5款工具帮你轻松实现合规隔离(2025亲测有效)
GooglePlay多账号管理实战指南:2025年高效合规工具与策略 在移动应用生态中,Google Play作为全球最大的应用分发平台,其严格的账号管理政策让许多开发者感到头疼。特别是对于那些需要运营多个账号的开发者来说,如何在合规前提下实…...
VisualGDB跨平台调试避坑指南:用VS远程调试Linux程序(2023最新版配置)
VisualGDB跨平台调试实战:2023年VS远程开发Linux程序避坑指南 当Visual Studio开发者首次尝试在Linux环境下进行C开发时,往往会面临调试工具链断裂的困境。传统的gdb命令行调试方式与Windows开发者熟悉的图形化调试体验存在巨大鸿沟,而Visual…...
Visual C++运行库一键修复终极指南:快速解决系统依赖问题
Visual C运行库一键修复终极指南:快速解决系统依赖问题 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist Visual C运行库是Windows系统中不可或缺的组件…...
Jetson Nano实战:FFmpeg与Nginx的RTMP推流配置全解析
1. Jetson Nano与RTMP推流基础认知 第一次接触Jetson Nano做视频推流时,我对着这块信用卡大小的开发板研究了整整三天。这块搭载了128核NVIDIA Maxwell GPU的小家伙,其实是个隐藏的视频处理高手。RTMP协议就像快递公司的"当日达"服务ÿ…...
新手零障碍入门:在免激活的快马平台完成你的第一个Python小游戏
作为一个刚接触编程的新手,我最近在InsCode(快马)平台上完成了人生第一个Python小游戏——猜数字。整个过程比想象中简单得多,特别适合像我这样零基础的小白入门。下面分享我的学习笔记,希望能帮到同样想尝试编程的朋友。 为什么选择猜数字游…...
BeanUtils vs MapStruct:Java对象拷贝工具选型指南(附性能对比测试)
BeanUtils vs MapStruct:Java对象拷贝工具深度评测与选型指南 在Java开发中,对象属性拷贝是几乎每个项目都会遇到的常见需求。从简单的DTO转换到复杂的领域模型映射,选择高效、稳定的拷贝工具直接影响代码质量和系统性能。本文将深入对比Apac…...
RK3568 Serdes方案调试:基于THCV244的I2C透传与MIPI CSI链路配置
1. RK3568与THCV244 Serdes方案概述 在车载摄像头和工业视觉应用中,Serdes(串行器/解串器)技术正变得越来越重要。RK3568作为一款高性能处理器,配合THCV244 Serdes芯片,能够实现远距离传感器数据的稳定传输。这套方案的…...
3个颠覆性用法:B站字幕提取工具如何改变你的视频创作流程
3个颠覆性用法:B站字幕提取工具如何改变你的视频创作流程 【免费下载链接】BiliBiliCCSubtitle 一个用于下载B站(哔哩哔哩)CC字幕及转换的工具; 项目地址: https://gitcode.com/gh_mirrors/bi/BiliBiliCCSubtitle 你是否曾经为了获取B站视频的字幕而烦恼&…...
深圳嵌入式技术产业创新与应用全景
1. 深圳嵌入式科技产业全景扫描 深圳作为中国科技创新高地,已形成全球最完整的嵌入式技术产业链。从消费电子到工业控制,从汽车电子到医疗设备,嵌入式系统正以"润物细无声"的方式重塑各个行业。这座城市聚集了超过2000家嵌入式相关…...
告别环境配置烦恼:用快马一键生成keil5兼容c51与stm32的完整安装指南
作为一名嵌入式开发者,我深知在Keil5中同时配置C51和STM32开发环境的痛苦。每次换电脑或者重装系统,都要花大半天时间折腾各种安装包、环境变量和驱动问题。最近发现InsCode(快马)平台可以一键生成完整的配置指南,简直拯救了我的开发效率。下…...
