【JavaEE】Java中的多线程 (Thread类)
作者主页:paper jie_博客
本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。
本文录入于《JavaEE》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将MySQL基础知识一网打尽,希望可以帮到读者们哦。
其他专栏:《MySQL》《C语言》《javaSE》《数据结构》等
内容分享:本期会对JavaEE中一个关于多线程的重要类Thread进行分享~
目录
什么是Thread
创建线程
继承Thread类
实现Runnable接口
匿名内部类创建Thread子类对象
匿名内部类创建Runnable子类对象
lambda表达式创建子类对象
Thread类的方法与常见属性
构造方法
常见属性
常用方法
启动线程 - start()
中断线程
引入标记
interrupt()
异常的原因
等待程序 - join()
获取当前线程引用 - currentThread()
什么是Thread
Thread类是在Java标准库中的,它可以视为是对操作系统提供的API进一步的抽象与封装. 一个Thread实例对象我们可以认为是一个线程.
创建线程
继承Thread类
这里需要继Thread类来创建一个线程类. 因为这里要重写run方法.里面就是这个线程需要执行的逻辑.
然后还需要创建它的实例,这样一个线程才算创建出来了. 最后需要调用start方法启动线程.
class MyThread extends Thread {@Overridepublic void run() {System.out.println("hello Thread");}
}
public class ThreadDemo1 {public static void main(String[] args) {Thread t = new MyThread();t.start();System.out.println("hello main");}
}
实现Runnable接口
创建Thread实例,调用Thread构造方法时将Runnable对象作为参数.
class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("线程运行代码");}
}
public class ThreadDemo2 {public static void main(String[] args) {Thread t = new Thread(new MyRunnable());t.start();System.out.println("hell main");}
}
匿名内部类创建Thread子类对象
这里后面是Thread类的匿名子类.
public class ThreadDemo3 {public static void main(String[] args) {Thread t = new Thread("这是我"){@Overridepublic void run() {System.out.println("这是匿名方法");while(true) {System.out.println("heeh");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}};t.start();}
}
匿名内部类创建Runnable子类对象
public class ThreadDemo4 {public static void main(String[] args) {Thread t = new Thread(new Runnable(){@Overridepublic void run() {System.out.println("匿名创建Runnable子类");}});t.start();}
}
lambda表达式创建子类对象
public class ThreadDemo5 {public static void main(String[] args) {Thread t = new Thread(() -> {System.out.println("lambda表达式创建子类对象");});t.start();}
}
Thread类的方法与常见属性
构造方法
这里第三个和第四个可以重命名,这样可以更好的进行调试.
常见属性
ID是这个线程的唯一表示,不同的线程ID是不会重复的
名称一般就是调试的时候可以用到
状态表示一个线程当前所处的情况.一般有就绪状态和堵塞状态
优先级表示线程是不是更容易被调度
前台线程的运行会阻止进程的结束,后台线程的运行不会阻止进程的结束.一个进程的结束需要等所有前台线程执行完才会结束,不然就算是main线程执行完了也不会结束.我们创建的线程默认都是前台线程.
是否存活简单来说就是run方法是否执行完了. Java中Thread实例虽然代表的是多线程,但是它的生命周期和内核中创建出来的线程PCB的生命周期不是一样的.
此时虽然Thread实例对象有了,但是内核中线程PCB还没创建,isAlive是false.只有在t.start()执行后内核中的PCB才会创建出来,这时isAlive为true
当run方法执行完后,内核中的PCB就销毁了,这时isAlive为false.
常用方法
启动线程 - start()
这里Thread实例对象虽然创建出来了,但是线程并未真正的启动.调用start()后才算真正的创建出了一个线程. 这里的start()才是在内核中创建出一个线程. 调用start()创建线程本质上就是调用系统的API来创建线程.
这里一个线程只能调用一次start(),再次使用start需要用另一个线程对象来调用.不然它会报出一个非法线程状态的异常.
public class ThreadDemo1 {public static void main(String[] args) {Thread thread = new Thread() {@Overridepublic void run() {System.out.println("线程");}};thread.start();thread.start();System.out.println("hell main");}
}
中断线程
中断一个线程就是提前让这个线程的run方法结束.常用的方法有两种:
1. 通过引入一个标记
2. 通过interrupt()方法
引入标记
这里通过flag这个标记来让run方法提前结束.当main线程执行到flag = true时,另一线程就会提前结束.
public class ThreadDemo2 {public static boolean flag = false;public static void main(String[] args) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {while(!flag) {System.out.println("hell Thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}});thread.start();try {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("终止这个线程");flag = true;}
}
这里注意,flag标识是不能在main方法内中,不能作为局部变量.虽然lambda匿名内部类可以通过变量捕捉访问到外面的局部变量.但是这个局部变量必须是不可变的,是final修饰的,这就和我们需要通过改变标记来终止线程发生冲突了,这就不可行.
必须是final是因为main方法和Thread都有自己的函数栈帧.他们生命周期不同.flag是在属于main的栈帧中,一但main执行完了,它的栈帧就会销毁,Thread再想使用就用不到了. 这里变量捕捉就是为了这个而诞生.它就是传参,本质上就是在需要的线程上将flag拷贝一份.为了保证flag的一致性就让它不能改变.
interrupt()
Thread里面自带一个标志位.我们可以通过方法来获取和改变这个标志位.
这里可以用Thread.interrupted()或者Thread.currentThread().isInterrupted()来获取内置的标志位.
interrupt()方法可以改变标志位.
这里使用了Thread.currentThread().isterrupted:
public class ThreadDemo3 {public static void main(String[] args) {Thread thread = new Thread(() -> {while(!Thread.currentThread().isInterrupted()) {System.out.println("hell Thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});thread.start();try {Thread.sleep(4000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("中断它");thread.interrupt();}
}
但运行代码后我们会发现问题:
这里会发现它会抛出一个中断异常,然后继续运行,并没有停下来.
异常的原因
这时因为这里interrupt()方法提前唤醒了sleep,这个时候sleep就会做两件事:
1. 抛出InterruptedExecption这个异常
2. 将内置标志位还原.
所有这会导致线程继续运行.
需要线程停下来,处理方法我们在catch里面加上break就可以了.
这里在catch中我们有三种处理方法:
1. 让线程立刻停下来
2. 让线程先运行一些代码再停下来
3. 让线程不停下来继续运行
我们处理异常也有几种常见的方法:
等待程序 - join()
join方法可以调整线程执行的先后顺序.虽然说线程的调度执行是随机调度的.但这里join可以将线程进行堵塞从而影响到了线程的执行先后顺序.join所在的线程会发生堵塞,在调用join方法线程运行完后,这个线程的堵塞状态才会解除.
注意: 这里是调用join()的线程被等待先执行,join()所在的线程等待,后执行.
join()方法有三种:
第一种: 死等,需要等等待的线程执行完才会解除堵塞状态
第二种: 有时间的等待, 在一定时间内进行堵塞.超出时间范围就会解除堵塞状态
第三种:精确到微秒的有时间等待.
一般情况下,我们最常用的就是第二种情况:
public class ThreadDemo4 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(() -> {while(true) {System.out.println("hell main");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});thread.start();thread.join();while(true) {System.out.println("hell ");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
这段代码,就是main线程进入堵塞状态,等待Thread线程结束. 虽然说Thread这个线程这执行中可以和其他多个线程共同进行调度执行,但由于main线程一直在等待,就算Thread线程在CPU上进行了多次切换也不影响这个线程先执行完.
这里注意: 我们的interrupt方法可以将join线程提前唤醒.
获取当前线程引用 - currentThread()
在使用类继承Thread创建线程方法我们可以用this直接引用这个对象.但是当使用lambda/匿名内部类/Runnable时this就不再指向Thread对象了.这时我们获取Thread对象引用就需要使用currentThread()方法了.
public class ThreadDemo7 {public static void main(String[] args) {Thread t = new Thread(() -> {System.out.println("hello Thread");System.out.println(Thread.currentThread().getName());});t.start();}
}
休眠当前线程 - sleep()
sleep可以将当前线程休眠一定时间,这个时间可以自己设定.但使用它需要抛出异常或者try- catch.这里休眠的时间因为线程调度的不可控,一般都会大于等于设定的时间.
它也有两种方法:
一般都是使用第一种,第二种是精确到微秒.
public class ThreadDemo8 {public static void main(String[] args) {Thread t = new Thread(() -> {try {Thread.sleep(1111);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("休眠1.111秒");});t.start();}
}
相关文章:

【JavaEE】Java中的多线程 (Thread类)
作者主页:paper jie_博客 本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。 本文录入于《JavaEE》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造&…...

python中具名元组的使用
collections.namedtuple是一个工厂函数,它可以用来构建一个带字段名的元组和一个有名字的类。 from collections import namedtuple City namedtuple(City2, name country population coordinates) tokyo City(Tokyo, JP, 36.933, (35.689722, 139.691667)) pr…...

【开题报告】基于SpringBoot的婚纱店试妆预约平台的设计与实现
1.选题背景 婚礼是人生中的重要时刻,而试妆是婚礼准备过程中不可或缺的一环。传统的婚纱店试妆预约方式通常需要亲自到店或通过电话预约,这样的方式可能存在一些问题。首先,用户需要花费时间和精力到店进行预约,对于忙碌的现代人…...

Qt 布局讲解及举例
Qt布局是一个用于管理窗口部件位置和大小的机制,它使得开发人员能够轻松地创建可伸缩、可调整大小的界面。在Qt中,布局管理器是一种用于自动调整窗口部件大小的机制,它可以根据窗口大小的变化自动调整部件的位置和大小。 Qt布局管理器通过使…...

【微服务】java 规则引擎使用详解
目录 一、什么是规则引擎 1.1 规则引擎概述 1.2 规则引擎执行过程 二、为什么要使用规则引擎 2.1 使用规则引擎的好处 2.1.1 易于维护和更新 2.1.2 增强应用程序的准确性和效率 2.1.3 加快应用程序的开发和部署 2.1.4 支持可视化和可管理性 2.2 规则引擎使用场景 三、…...

HCIA-Datacom跟官方路线学习
通过两次更换策略。最后找到最终的学习方案,华为ICT官网有对这个路线的学习,hcia基础有这个学习路线,hcip也有目录路线。所以,最后制定学习路线,是根据这个认证的路线进行学习了: 官网课程:课程…...

MySQL三大日志详细总结(redo log undo log binlog)
MySQL日志 包括事务日志(redolog undolog)慢查询日志,通用查询日志,二进制日志(binlog) 最为重要的就是binlog(归档日志)事务日志redolog(重做日志)undolog…...

XXL-Job详解(二):安装部署
目录 前言环境下载项目调度中心部署执行器部署 前言 看该文章之前,最好看一下之前的文章,比较方便我们理解 XXL-Job详解(一):组件架构 环境 Maven3 Jdk1.8 Mysql5.7 下载项目 源码仓库地址链接: https://github.…...

支持Arm CCA的TF-A威胁模型
目录 一、简介 二、评估目标 2.1 假定 2.2 数据流图 三、威胁分析 3.1 威胁评估 3.1.1 针对所有固件镜像的一般威胁 3.1.2 引导固件可以缓解的威胁...

【Web端CAD/CAE文字标注】webgl+canvas 2d实现文字标注功能
一、需求背景 在CAD/CAE领域经常会遇到显示节点编号这种需求,效果如下图: 本文介绍如何在WebGL中实现文字的显示,对于如何在OpenGL中实现请绕路。 二、实现原理 Canvas是HTML5提供的元素,用于在网页上绘制图形,其支…...

对话框、内部控件位置
一、了解下几个函数 1、movewindow 了解下:MoveWindow 自己塞进去的是屏幕坐标 CrvtFaultRodDlg* dlg new CrvtFaultRodDlg();if (dlg ! NULL){BOOL ret dlg->Create(IDD_DlgCrvtFaultRod, NULL);if (ret) //Create failed.{RECT rect;{RECT rect1;dlg->…...

【GraphQL 】将GraphQL API添加到Postgres数据库的六种简单方法,比较Hasura、Prisma和其他
PostgreSQL是世界上最流行的开源SQL数据库之一,GraphQL是一种日益流行的API规范。 将经过验证和众所周知的PostgreSQL与GraphQL带来的API创建新方式集成在一起不是很好吗? 在本文中,我们讨论了六个不同的项目,它们试图将SQL与Gr…...

每日一题(LeetCode)----哈希表--有效的字母异位词
每日一题(LeetCode)----哈希表–有效的字母异位词 1.题目(242. 有效的字母异位词) 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互…...

【设计模式】行为型模式-第 3 章第 6 讲【中介者模式】
目录 定义 场景描叙 目的 主要解决 实现 基本类图 案例代码...

Django 通过 Trunc(kind) 和 Extract(lookup_name) 参数进行潜在 SQL 注入 (CVE-2022-34265)
漏洞描述 Django 于 2022 年6月4 日发布了一个安全更新,修复了 Trunc() 和 Extract() 数据库函数中的 SQL 注入漏洞。 参考链接: Django security releases issued: 4.0.6 and 3.2.14 | Weblog | Djang…...

Vue3-toRef 和 toRefs 函数
Vue3-toRef 和 toRefs 函数 功能:可以简化语法调用。toRef 函数执行时会生成一个对象 ObjectRefImpl ,是一个引用对象,具有value属性(getter 和 setter 属性)语法格式:toRef(对象名, 对象中的属性名) toRe…...

STM32---时钟树
写在前面:一个 MCU 越复杂,时钟系统也会相应地变得复杂,如 STM32F1 的时钟系统比较复杂,不像简单的 51 单片机一个系统时钟就 可以解决一切。对于 STM32F1 系列的芯片,其有多个时钟源,构成了一个庞大的是时…...

【功能测试】软件系统测试报告
1.引言 1.1.目的 本测试报告为 xxx 系统测试报告,本报告目的在于总结测试阶段的测试及测试结果分析,描述系统是否达到需求的目的。 本报告预期参考人员包括测试人员、测试部门经理、开发人员、项目管理人员等。 1.2.参考文档 《xxxx系统需求规格说明…...

CentOS一键安装docker脚本
CentOS安装Docker一键脚本 在CentOS上安装Docker是许多项目中常见的任务之一。为了简化这个过程,你可以使用下面的一键脚本。 #!/bin/bash# 卸载旧版本(如果有) sudo yum remove -y docker \docker-client \docker-client-latest \docker-c…...

PostGIS学习教程八:空间关系
PostGIS学习教程八:空间关系 到目前为止,我们只使用了测量(ST_Area、ST_Length)、序列化(ST_GeomFromText)或者反序列化(ST_AsGML)几何图形(geometry)的空间…...

ESP32-Web-Server编程- 通过文本框向 Web 提交数据
ESP32-Web-Server编程- 通过文本框向 Web 提交数据 概述 前述章节我们通过简单 HTML、AJAX、Websocket、SSE 在网页上显示数据,通过网页上的按钮控制 ESP32 的行为。从本节开始,我们将进一步了解通过网页与 ESP32 进行交互的方法。 实现更复杂的交互功…...

NAT网络地址转换
目录 什么是nat nat 实验如何使用SNAT 和 DNAT 实验环境 内网连接外网 1.给网关服务器添加网卡(两张网卡) 2.查看新添加的网卡名 编辑网卡配置 3.开启路由转发 4.打开内网服务器 5.切换到外网服务器(192.168.17.30࿰…...

PyTorch模型训练过程内存泄漏问题解决
近日,在模型训练过程中,发现过一段时间后进程会被kill,观察发现是由于内存泄漏问题造成的。通过逐行代码注释,发现问题在于数据集中的此行代码: info self.data_list[index]这里,self.data_list是dataset…...

【matlab程序】matlab利用工具包nctool读取grib2、nc、opendaf、hdf5、hdf4等格式数据
【matlab程序】matlab利用工具包nctool读取grib2、nc、opendaf、hdf5、hdf4等格式数据 引用: B. Schlining, R. Signell, A. Crosby, nctoolbox (2009), Github repository, https://github.com/nctoolbox/nctoolbox Brief summary: nctoolbox is a Matlab toolbox…...

pytorch训练模板
来源:http://worthpen.top/#/home/blog?blogpot-blog36.md 引言 本项目实现了基于PyTorch Lightning的神经网络训练和测试管道。项目除了实现PyTorch Lightning的工作流外,还实现了通过任务池在训练过程中添加任务、k折交叉验证、将训练结果保存在.cv…...

代码随想录二刷 |字符串 |反转字符串
代码随想录二刷 |字符串 |反转字符串 题目描述解题思路 & 代码实现 题目描述 344.反转字符串 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间,你必须…...

Rust语言入门教程(九) - 结构体
格式及语法 在其他很多编程语言中,有类(Class)的存在,在Rust中,我们没有类(Class)的概念,我们使用结构体(Struct)。 与一个结构体相关的有以下几个部分: 数据字段方法关联函数 声明一个结构体及其字段的格式如下&am…...

如何使用Qchan搭建更好保护个人隐私的本地图床并在公网可访问
文章目录 前言1. Qchan网站搭建1.1 Qchan下载和安装1.2 Qchan网页测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar云端设置2.2 Cpolar本地设置 3. 公网访问测试总结 前言 图床作为云存储的一项重要应用场景,在大量开发人员的努力下,已经开发出大…...

AI伪原创软件-AI伪原创工具下载
在当今数字化时代,创作者们在追求独特创意的同时,也面临着时间和灵感的双重挑战。AI伪原创技术应运而生,为创作者提供了一种快捷而便利的解决方案。本文将专心分享两款备受瞩目的AI伪原创工具,147SEO伪原创、百度文心一言伪原创&a…...

【python脚本】获取OneNET数据写入本地文件
#!/usr/bin/env python # -*- coding: utf-8 -*- # pip install prettytable import time import urllib.request as req import json import os# 设备ID、Key # ESP-12F deviceId "1047311396" APIKey "z0Yq8d3P16l2SbEwuZcXZuCidM"# 上传函数 def OneN…...