Javaee---多线程(一)
文章目录
- 1.线程的概念
- 2.休眠里面的异常处理
- 3.实现runnable接口
- 4.匿名内部类子类创建线程
- 5.匿名内部类接口创建线程
- 6.基于lambda表达式进行线程创建
- 7.关于Thread的其他的使用方法
- 7.1线程的名字
- 7.2设置为前台线程
- 7.3判断线程是否存活
- 8.创建线程方法总结
- 9.start方法
- 10.终止(中断)线程-interrupt
- 10.1自定义标志位
- 10.2使用系统里面的标志位
- 11.线程等待join
- 12.线程方法总结
- 11.线程等待join
- 12.线程方法总结
1.线程的概念
(下面的这个图片里面的代码有错误,我们new的这个mythread类的对象,应该是使用这个Thread这个类进行接收,这个是个向上转型的过程);
- 我们的这个里面使用到了这个thread类,但是不需要进行这个import的操作,这个主要就是因为我们的这个Thread是位于这个java.lang这个包下面的;像我们之前使用的这个String也是在这个包下面,我们也没有进行这个import的操作;
- 这个Thread里面是有这个run方法的,我们的这个mythread类里面对于这个夫类里面的方法进行了重写;
- 我们的main方法里面执行这个start时候,就会进入这个run入口进而对于这个内容进行打印输出;
实际上打印输出的时候main方法里面的内容和我们的自定义类里面的这个内容是独立进行的,两个并不会相互依赖;每一个线程都是一个独立的执行流;
当我们把这个start修改为这个run之后,这个就会先去执行我们自己的自定义类里面的这个重写的run方法,这个执行完成之后才会继续执行这个下面的helli main打印输出,但是因为我们的这个是死循环,因此这个会一直打印输出我们的hello thread;
2.休眠里面的异常处理
为了更加清楚的看到这个打印的效果,我们可以对于这个程序进行休眠操作,就是使用这个sleep方法,但是这个方法在进行使用的时候可能会出现一些问题,就是异常情况,针对于自定义类和main方法里面的异常,我们的处理手段是不一样的:
下面的这个异常是受查异常,需要进行显示处理:要么throws,要么try-catch
重写父类的方法,父类的方法里面没有throws,因此我们不可以throws;
相比之下,在这个main里面的这个内容都是我们自己写的,因此这个时候我们就可以使用这个throws方法对于这个出现的异常进行抛出;
有了上面的两个休眠的操作,这个时候我们重新运行这个程序,这个时候就会发现这个两个语句的打印输出的速度就变慢了,但是这个出现的先后顺序其实并不是确定的,这个主要取决于我们的操作系统对于这个线程的调度(调度器)的具体实现,因此我们可以看到有的时候是这个hello thread先打印输出,但是有的时候是这个hello main先打印输出;
3.实现runnable接口
下面的这个就是实现我们的这个runnable接口的方式,两个类里面的这个异常的处理方式还是一样的,一个是捕捉异常,一个就是抛出异常;
但是在这个主方法里面,我们使用这个已有的MyRunnable类实例化对象,相当于是定义了一个任务,然后我们吧这个传递到我们的这个new Thread这个参数里面去,相当于就是使用这个Thread去执行这个任务,其他的和上面的这个方式是没有任何区别的;
针对于这个方式,实现了这个runnable接口的这个类的实例化对象作为我们的这个Thread接口的构造方法的参数,这个和上面最大的不同就是解耦合:耦合指的就是我们的一个程序里面的不同模块之间的影响的程序,解耦合就是解除不同的模块之间的相互的影响;
这样的解耦合的好处就是我们只是定义了这个任务,但是交给谁去执行这个任务就没那么重要了,这个就是这个实现接口的方式和上面的最大不同;
4.匿名内部类子类创建线程
public class Test {public static void main(String[] args) throws InterruptedException {//匿名内部类,不知道这个类叫什么,但是知道这个类是我们的Thread的子类//不知道这个类的名字也不重要,因为这个类我们只会使用一次//下面的这个new后面的这个其实就可以理解为是一个类,使用这个没有名字的类实例化对象,在这个匿名的类里面对于这个方法进行重写,里面的这个对于异常的处理和定义两个类的时候是一样的;Thread t = new Thread(){@Overridepublic void run() {while(true){System.out.println("hello thread!");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}};//使用我们创建的这个线程去开始这个线程的执行,start就是这个线程执行的入口t.start();while(true){System.out.println("hello main!");Thread.sleep(1000);}}
}
5.匿名内部类接口创建线程
public class Test {public static void main(String[] args) throws InterruptedException {//匿名内部类,不知道这个类叫什么,但是知道这个类是我们的Thread的子类//不知道这个类的名字也不重要,因为这个类我们只会使用一次//下面的这个就是我们不知道这个类叫什么名字,但是这个类实现了这个接口Runnable//因此在这个匿名内部类里面对于这个接口里面的方法进行了重写Runnable runnable = new Runnable() {@Overridepublic void run() {while(true){System.out.println("hello thread!");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}};//这个就是我们的这个实现接口的类的实例化对象作为一个参数进行传递Thread t=new Thread(runnable);t.start();while(true){System.out.println("hello main!");Thread.sleep(1000);}}
}
6.基于lambda表达式进行线程创建
lambda实际上是这个匿名内部类的一个简化的方式:本质上就是一个函数表达式
public class test {public static void main(String[] args) throws InterruptedException {//lambda表达式是一个匿名函数,主要是实现回调函数的效果//回调函数是计算机里面的一个很重要的术语//回调函数--函数指针:函数指针实现转移表,减少if-else分支数目//使用函数指针作为回调函数--实现qsort()的比较//其实这个lambda表达式并不是很复杂,形式上就是这个()->{},我们的这个相关的代码就是写在这个大括号 里面的Thread t = new Thread(()->{while(true){System.out.println("hello thread!");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();while(true){System.out.println("hello main!");Thread.sleep(1000);}}
}
7.关于Thread的其他的使用方法
上面我们介绍两个:
1.直接调用无参数的,就是我们最开始介绍的;
2.传递的参数是我们的实现接口的类的实例化对象;
除此之外,我们还可以传递name参数,给这个线程起名字,对于线程进行区分:
7.1线程的名字
public class Test {public static void main(String[] args) {//String name;Thread t = new Thread(() -> {while(true){System.out.println("hello thread!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}},"这个是新的线程" );//上面的这个就是相当于是在原来的这个表达式的后面多了这个name属性,这样我们使用这个jconsole工具 进行查看的时候,我们就可以看到自己对于这个线程的命名了;t.start();}
}
7.2设置为前台线程
还是上面的这个程序,其实在这个默认的情况下,这个线程就是前台线程,就是我们的这个线程不结束,这个程序就不会结束,但是我们的后台线程就是这个线程结束与否,对于我们的整个程序的结束没有影响;
这个默认情况下是前台线程,我们可以使用这个setDaemon方法把这个线程设置为后台的线程;
我们的这个具体的差别可以在打印的时候看出来,就是我们的这个内容好像没有进行打印,这个程序就结束了;
public class Test {public static void main(String[] args) {//String name;Thread t = new Thread(() -> {while(true){System.out.println("hello thread!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}},"这个是新的线程" );//设置为后台的线程,运行起来就不会进行打印t.setDaemon(true);t.start();}
}
7.3判断线程是否存活
这个就是使用的t.isAlive方法判断这个线程是不是存活的,下面的这个使用start开始的时候,就是存活的线程,打印输出的结果就是true,但是休眠之后,这个就是死亡的,打印输出false;
public class Test {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{System.out.println("线程开始");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程结束");});t.start();System.out.println(t.isAlive());Thread.sleep(2000);System.out.println(t.isAlive());}
}
8.创建线程方法总结
9.start方法
start和run方法的区别:
我们的start方法会去调用这个系统里面的api,进行线程的创建;
run只会去执行这个线程里面的内容(会在这个start创建线程之后自动被调用);
两个的本质区别就是是不是调用了这个系统里面的api,创建出来了新的线程;
10.终止(中断)线程-interrupt
10.1自定义标志位
需要注意的就是这个自定义的静态的变量需要是全局的,不可以是局部的,因为这个lambda是变量的捕捉,这个变量需要是这个final或者是视为这个final的变量;
我们的这个变量一旦写作这个局部的,这个时候我们下面不可以进行修改了,但是我们的有修改,所以写成局部的就会报错,大家可以自己去尝试一下,看看这个效果,这个主要是lambda的语法导致的;
10.2使用系统里面的标志位
为什么会有下面的这个,因为上面的存在缺陷,就是我们需要手动创建,而且我们的线程如果正在休眠,我们把这个标志位修改掉,这个线程无法及时的做出回应,或者是叫做响应;
但是如果我们使用这个系统里面的标志位,这个就是currentThread().isInterrupted()方法进行判断当前的这个线程是不是被打断了;
我们的这个里面有一个t.sleep()这个方法就是进行线程的唤醒,上面的这个手动创建标志位的方法,如果我们的这个线程在休眠,这个时候不可以及时的进行响应,但是我们的这个interrupt这个方法,就会触发这个线程的异常,让这个休眠的线程提前被唤醒,但是我们在运行的时候会发现这个会抛出异常之后,还是会继续执行的;
这个主要原因就是我们的interrupt唤醒这个线程之后,我们的异常抛出把这个设置的标志位清除掉了,就是我们的自动设置的标志位没有了效果,我们的异常让这个标志位的效果失效了,接下来,线程可以自己决定接下来如何进行处理;
11.线程等待join
下面的这个程序就是我们的t线程会休眠,我们的t.join就会让这个主线程等待我们的t线程,直到我们的t线程执行结束,主线程才会结束;
12.线程方法总结
动设置的标志位没有了效果,我们的异常让这个标志位的效果失效了,接下来,线程可以自己决定接下来如何进行处理;
11.线程等待join
下面的这个程序就是我们的t线程会休眠,我们的t.join就会让这个主线程等待我们的t线程,直到我们的t线程执行结束,主线程才会结束;
12.线程方法总结
相关文章:

Javaee---多线程(一)
文章目录 1.线程的概念2.休眠里面的异常处理3.实现runnable接口4.匿名内部类子类创建线程5.匿名内部类接口创建线程6.基于lambda表达式进行线程创建7.关于Thread的其他的使用方法7.1线程的名字7.2设置为前台线程7.3判断线程是否存活 8.创建线程方法总结9.start方法10.终止&…...

Java后端面试内容总结
先讲项目背景,再讲技术栈模块划分, 讲业务的时候可以先讲一般再特殊 为什么用这个,好处是什么,应用场景 Debug发现问题/日志发现问题. QPS TPS 项目单元测试,代码的变更覆盖率达到80%,项目的复用性高…...

DC-1渗透测试
DC1 五个flag的拿取(截图是五个flag里面的内容) 注意事项:kali的用户名:root 密码:kali 注意:DC1 只要开机服务就起来了 思路:信息收集—> 寻找漏洞—> 利用漏洞(sql注入,文件上传漏洞…...

深度剖析:电商 API 接口如何成就卓越用户体验
在电商领域的激烈竞争中,提供卓越的用户体验已成为企业脱颖而出的关键。而电商 API 接口在其中扮演着举足轻重的角色,它如同电商平台的神经系统,连接着各个关键环节,为用户带来无缝、高效且个性化的购物之旅。 一、极速响应&#…...

C++调试经验:Ubuntu下CMake链接常见库的方式(持续更新)
目录 1. CMake链接OpenCV库 2. CMake链接VTK库 3. CMake链接Qt库 4. CMake链接PCL库 5. CMake链接Gstreamer 6. CMake链接json-cpp库 7. CMake链接yaml-cpp库 8. CMake链接breakpad库 9. CMake链接Eigen3库 1. CMake链接OpenCV库 find_package (OpenCV 4 REQUIRED)…...

【HarmonyOS】应用实现APP国际化多语言切换
【HarmonyOS】应用实现APP国际化多语言切换 前言 在鸿蒙中应用国际化处理,与Android和IOS基本一致,都是通过JSON配置不同的语言文本内容。在UI展示时,使用JSON配置的字段key进行调用,系统选择对应语言文本内容。 跟随系统多语言…...

使用pandas进行数据分析
文章目录 1.pandas的特点2.Series2.1新建Seriws2.2使用标签来选择数据2.3 通过指定位置选择数据2.4 使用布尔值选择数据2.5 其他操作2.5.1 修改数据2.5.2 统计操作2.5.3 缺失数据处理 3.DataFrame3.1 新建 DataFrame3.2 选择数据3.2.1 使用标签选择数据3.2.2 使用 iloc 选择数据…...

用于无监督域适应的提示分布对齐
论文探讨了视觉语言模型(VLMs)及其在无监督域适应(UDA)中的应用,并引入了一种名为提示分布对齐(Prompt-based Distribution Alignment,PDA)的方法,该方法采用双分支训练策…...

Rust整合Elasticsearch
Elasticsearch是什么 Lucene:Java实现的搜索引擎类库 易扩展高性能仅限Java开发不支持水平扩展 Elasticsearch:基于Lucene开发的分布式搜索和分析引擎 支持分布式、水平扩展提高RestfulAPI,可被任何语言调用 Elastic Stack是什么 ELK&a…...

Linux 文件权限管理:chown、chgrp 和 chmod 的使用及权限掩码规则
目录 文件权限的基本概念 chown:更改文件的拥有者 使用方法 示例 选项 chgrp:更改文件的所属组 使用方法 示例 chmod:更改文件的权限 使用方法 权限表示 选项 权限掩码(umask)规则 如何查看和设置 umask…...

简单记录ios打包流程
1、点击这里获取UDID 2、xcode登录开发者账户、确定唯一id(Bundle ID) 3、去这里注册appid 4、在这里这里创建app 5、之后xcode中打包...

右键以vscode打开目录的时候出现找不到应用程序
出现这个问题的主要原因,大概率可能是因为你移动了vscode的安装路径导致的。 解决办法 打开注册表:通过cmd 打开regedit 然后搜索:计算机\HKEY_CLASSES_ROOT\Directory\Background\shell 这个两个参数可以自己比对一下,主要需要检…...

【Go-Taskflow:一个类似任务流的有向无环图(DAG)任务执行框架,集成了可视化和性能分析工具,旨在简化并行任务的复杂依赖管理】
Go-Taskflow是一个静态有向无环图(DAG)任务计算框架,它受到taskflow-cpp的启发,结合了Go语言的原生能力和简洁性,特别适合于并发任务中复杂的依赖管理。 Go-Taskflow的主要特点包括: 高可扩展性࿱…...

排查PHP服务器CPU占用率高的问题
排查PHP服务器CPU占用率高的问题通常可以通过以下步骤进行: 使用top或htop命令:这些命令可以实时显示服务器上各个进程的CPU和内存使用情况。找到CPU使用率高的进程。 查看进程日志:如果PHP-FPM或Apache等服务器进程的日志记录了具体的请求…...

【学术会议论文投稿】“从零到一:使用IntelliJ IDEA打造你的梦幻HTML项目“
【JPCS独立出版】2024年工业机器人与先进制造技术国际学术会议(IRAMT 2024)_艾思科蓝_学术一站式服务平台 更多学术会议请看 学术会议-学术交流征稿-学术会议在线-艾思科蓝 目录 引言:为何选择IntelliJ IDEA? 第一步:…...

Win11安装基于WSL2的Ubuntu
1. 概述 趁着还没有完全忘记,详细记录一下在Win11下安装基于WSL2的Ubuntu的详细过程。不得不说WSL2现在被微软开发的比较强大了,还是很值得安装和使用的,笔者就通过WSL2安装的Ubuntu成功搭建了ROS环境。 2. 详论 2.1 子系统安装 在Win11搜…...

如何对pdf文件进行加密?pdf文件加密全攻略与深度解析(5个方法)
如何对pdf文件进行加密? 只见,在深夜的情报局里,特工小李将一份绝密PDF文件放在保险箱内,以为这样就天衣无缝了。 细细推敲,漏洞百出: 如果钥匙被盗呢?如果被神匠破解出密码呢?如果…...

c++面向对象三大特性之一-----多态
前言:本文将介绍在32位平台下,c的多态,通过本篇文章的学习你讲了解多态的原理,多态的底层还有一些不常见的关键字的介绍(final,override). 文章内容如下: 1:多态的概念 2:多态的定义与实现 3:多态的原理 4:抽象类 文章正式开始 1:多态的概念 多…...

8.Linux按键驱动-中断下半部
1.编程思路 1.1在gpio结构体中添加tasklet_struct结构体 1.2在probe函数中初始化tasklet结构体 1.3在中断服务程序中调度tasklet 1.4在这个函数中执行其它任务 2.代码: 应用程序和Makefile和上节一致 https://blog.csdn.net/weixin_40933496/article/details/1…...

Redis 线程控制 总结
前言 相关系列 《Redis & 目录》(持续更新)《Redis & 线程控制 & 源码》(学习过程/多有漏误/仅作参考/不再更新)《Redis & 线程控制 & 总结》(学习总结/最新最准/持续更新)《Redis &a…...

Scrapy框架原理与使用流程
一.Scrapy框架特点 框架(Framework)是一种软件设计方法,它提供了一套预先定义的组件和约定,帮助开发者快速构建应用程序。框架通常包括一组库、工具和约定,它们共同工作以简化开发过程。scrapy框架是python写的 为了爬…...

【C语言】字符型在计算机中的存储方式
ASCII对照表:https://www.jyshare.com/front-end/6318/ ASCII(American Standard Code for Information Interchange,美国信息互换标准代码,ASCII)是基于拉丁字母的一套电脑编码系统。它主要用于显示现代英语和其他西…...

python:ADB通过包名打开应用
一、依赖库 os 二、命令 1.这是查看设备中所有应用包名的最简单方法。只需在命令行中输入以下命令: adb shell pm list packages 2.打印启动的程序包名 adb shell am monitor回车,然后启动你想要获取包名的那个应用,即可获得 3.查看正在运…...

机器翻译技术:AI 如何跨越语言障碍
大家好,我是Shelly,一个专注于输出AI工具和科技前沿内容的AI应用教练,体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具,拥抱AI时代的到来。 AI工具集1:大厂AI工具【共23款…...

单调栈应用介绍
单调栈应用介绍 定义应用场景实现模板具体示例下一个最大元素I问题描述问题分析代码实现柱状图中最大的矩形问题描述问题分析代码实现接雨水问题描述问题分析代码实现最大宽度坡问题描述问题分析代码实现132模式问题描述问题分析代码实现定义 栈(Stack)是另一种操作受限的线性…...

部署前后端分离若依项目--CentOS7Docker版
一、准备 centos7虚拟机或服务器一台 若依前后端分离项目:可在下面拉取 RuoYi-Vue: 🎉 基于SpringBoot,Spring Security,JWT,Vue & Element 的前后端分离权限管理系统,同时提供了 Vue3 的版本 二、环…...

PH47代码框架功能速查
1. PH47框架逻辑层全局引用对象 全局引用 功能简介 快速访问 bus 数据总线系统功能实现,如对总线数据项读写操作等 数据总线bus drv 驱动层功能实现,如飞控板相关的各种硬件传感器设备进行操作等 驱动层drv mcu 对mcu的片内接口及设备进行操作…...

UVM寄存器模型:uvm_reg_adapter
文章目录 一、什么是uvm_reg_adapter1、what2、Example2.1、代码详解 二、如何使用uvm_reg_adapter三、为什么要引入uvm_reg_adapter 一、什么是uvm_reg_adapter 1、what uvm_reg_adapter继承于uvm_object,定义了用于在 uvm_reg_bus_op 和特定总线事务之间进行转换…...

总结OpenGL和pyrender安装和使用过程中的坑
目录 报错一:AttributeError: NoneType object has no attribute glGetError 报错二:ImportError: (Unable to load OpenGL library, OSMesa: cannot open shared object file: No such file or directory, OSMesa, None) 报错三:raise ImportError("Unable to load…...

温湿传感器(学习笔记下)
接着我们温湿传感器上半部分的学习,现在我们学习接下来的部分,编写GXHTC3驱动程序,也就是给gxhtc3.c文件添加代码,我们要判断gxhtc3芯片是否存在和正常,就要先读取gxhtc3的ID号,根据gxhtc3的数据手册,读取命…...