当前位置: 首页 > news >正文

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入口进而对于这个内容进行打印输出;

image-20241019192827539

实际上打印输出的时候main方法里面的内容和我们的自定义类里面的这个内容是独立进行的,两个并不会相互依赖;每一个线程都是一个独立的执行流;

image-20241019211712898

当我们把这个start修改为这个run之后,这个就会先去执行我们自己的自定义类里面的这个重写的run方法,这个执行完成之后才会继续执行这个下面的helli main打印输出,但是因为我们的这个是死循环,因此这个会一直打印输出我们的hello thread;

image-20241019211737878

2.休眠里面的异常处理

为了更加清楚的看到这个打印的效果,我们可以对于这个程序进行休眠操作,就是使用这个sleep方法,但是这个方法在进行使用的时候可能会出现一些问题,就是异常情况,针对于自定义类和main方法里面的异常,我们的处理手段是不一样的:

下面的这个异常是受查异常,需要进行显示处理:要么throws,要么try-catch

重写父类的方法,父类的方法里面没有throws,因此我们不可以throws;

image-20241020212336753

image-20241020212513823

相比之下,在这个main里面的这个内容都是我们自己写的,因此这个时候我们就可以使用这个throws方法对于这个出现的异常进行抛出;

image-20241020213545037

有了上面的两个休眠的操作,这个时候我们重新运行这个程序,这个时候就会发现这个两个语句的打印输出的速度就变慢了,但是这个出现的先后顺序其实并不是确定的,这个主要取决于我们的操作系统对于这个线程的调度(调度器)的具体实现,因此我们可以看到有的时候是这个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.创建线程方法总结

image-20241021125053812

9.start方法

start和run方法的区别:

我们的start方法会去调用这个系统里面的api,进行线程的创建;

run只会去执行这个线程里面的内容(会在这个start创建线程之后自动被调用);

两个的本质区别就是是不是调用了这个系统里面的api,创建出来了新的线程;

10.终止(中断)线程-interrupt

10.1自定义标志位

需要注意的就是这个自定义的静态的变量需要是全局的,不可以是局部的,因为这个lambda是变量的捕捉,这个变量需要是这个final或者是视为这个final的变量;

我们的这个变量一旦写作这个局部的,这个时候我们下面不可以进行修改了,但是我们的有修改,所以写成局部的就会报错,大家可以自己去尝试一下,看看这个效果,这个主要是lambda的语法导致的;

image-20241021132639605

10.2使用系统里面的标志位

为什么会有下面的这个,因为上面的存在缺陷,就是我们需要手动创建,而且我们的线程如果正在休眠,我们把这个标志位修改掉,这个线程无法及时的做出回应,或者是叫做响应;

但是如果我们使用这个系统里面的标志位,这个就是currentThread().isInterrupted()方法进行判断当前的这个线程是不是被打断了;

我们的这个里面有一个t.sleep()这个方法就是进行线程的唤醒,上面的这个手动创建标志位的方法,如果我们的这个线程在休眠,这个时候不可以及时的进行响应,但是我们的这个interrupt这个方法,就会触发这个线程的异常,让这个休眠的线程提前被唤醒,但是我们在运行的时候会发现这个会抛出异常之后,还是会继续执行的;

这个主要原因就是我们的interrupt唤醒这个线程之后,我们的异常抛出把这个设置的标志位清除掉了,就是我们的自动设置的标志位没有了效果,我们的异常让这个标志位的效果失效了,接下来,线程可以自己决定接下来如何进行处理;

image-20241021174301710

11.线程等待join

下面的这个程序就是我们的t线程会休眠,我们的t.join就会让这个主线程等待我们的t线程,直到我们的t线程执行结束,主线程才会结束;

image-20241021181517994

12.线程方法总结

image-20241021183414460
动设置的标志位没有了效果,我们的异常让这个标志位的效果失效了,接下来,线程可以自己决定接下来如何进行处理;

在这里插入图片描述

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的主要特点包括: 高可扩展性&#xff1…...

排查PHP服务器CPU占用率高的问题

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

【学术会议论文投稿】“从零到一:使用IntelliJ IDEA打造你的梦幻HTML项目“

【JPCS独立出版】2024年工业机器人与先进制造技术国际学术会议(IRAMT 2024)_艾思科蓝_学术一站式服务平台 更多学术会议请看 学术会议-学术交流征稿-学术会议在线-艾思科蓝 目录 引言:为何选择IntelliJ IDEA? 第一步&#xff1a…...

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…...

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...