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

【JavaEE】Thread 类及常用方法


一、Thread 类

Thread 类我们可以理解为是 java 用于管理线程的一个类,里面封装了操作系统提供的线程管理这一方面的 API (Thread 是优化后的结果), Java 代码创建的每一个线程,可以理解为为 Thread 实例化的对象,Thread 对象用于描述线程的信息。

Java 标准库中 Thread 类可以视为是对操作系统对线程管理方面提供的 API 进行了进一步的抽象和封装.

API : Application Programing linerface

给你一个软件,你能对他干什么,基于它提供的这些功能,就可以写一些代码,然后封装在一起,方便别人使用。

编辑计算机通常只有一个CPU(多核心),单核心在任意时刻只能执行一条机器指令,每个线程只有获得CPU的使用权才能执行指令。所谓多线程的并发运行,其实是指从宏观上看,各个线程轮流获得CPU的使用权,分别执行各自的任务。在运行池中,会有多个处于就绪状态的线程在等待CPU,JAVA虚拟机的一项任务就是负责线程的调度,线程调度是指按照特定机制为多个线程分配CPU的使用权。


1.1 Thread 的常见构造方法

方法名

解释:

Thread()

创建线程对象

Thread( Runnable target )

使用 Runnable对象创建线程对象

Thread( String name )

创建线程对象,并为其命名 (方便辨认)

Thread(Runnable target, String name)

使用 Runnable 对象创建线程对象,并命名

Thread(ThreadGroup group,Runnable target)

线程可以被用来分组管理,分好的组即为线程组。

二、 Thread 的常见属性

属性

获取方法

ID

getId()

名称

getName()

状态

getState()

优先级

getPriority()

是否后台线程

isDaemon()

是否存活

isAlive()

是否被中断

isInterrupted()

返回对当前正在执行的线程对象的引用

Thread.currentThread

ID :每个线程创建的是时候都会有一个唯一的 id,不同线程不会重复

名称:给每个线程起一个别名,例如:语言通话进程,文字交流进程,动态分享进程,调试进程的时候方便辨别。


2.1 启动一个线程

java 代码创建线程的方法主要有三种


自定义类继承 Thread 类 ,重写父类 run 方法

自定义类实现Runnable 接口,重写 run 方法

lambda 表达式,不依托类,直接指向 run 方法重写

采用 lambda表达式创建线程对象

publicstaticvoidmain(String[] args){Thread t = newThread(() -> { //采用 lambda表达式创建线程对象System.out.println("线程 t 启动");});
​t.start(); // 启动线程,从启动开始就有两个线程流参与 CPU 的调度执行
​System.out.println("主线程 main");
}

我们创建了一个线程对象,然后重写父类的 run 方法,这并不意味着线程就可以运行了。

线程的 run 方法, 我们可以理解为主线程的 main() 方法, 我们刚开始接触编程的时候,应该都听过程序是从 main () 函数开始执行的, 此时 run 方法,就可以认为是 另一个线程的 main() 方法,多线程并发执行。run 方法中就是我们程序的另一个执行流。

例如: qq 在打视频电话的时候,同时也可以接收qq 消息, 视频电话是一个线程,聊天窗口也是个线程,并发执行,互不干扰,此时我们把 qq 聊天窗口当作是 main() 方法,qq 视频通话当作是 t 线程的 run() 方法, 两个线程同属于 qq 这个进程, 当我们 启动qq 时,(一个进程中必须包含一个线程,线程是系统调度的基本单位)默认启动的是 主线程执行main()方法 , qq 一打开,聊天消息响不停,没有问题,我们不启动qq 视频电话或者是没有好友打来电话,t 线程不会被启动,这并不意味着 qq视频通话的功能不存在,需要的是手动或者是被动的启动, 那么 t 线程启动的方式就是调用我们的 t.start() 方法 ,此时 t 线程才是真正的独立的执行了,我们点击视频通话的操作就可以想象为调用了线程的start 方法启动。

调用了 start() 方法,此时真正的在操作系统的底层创建出一个可以被调度执行的线程。


2.2 获取当前线程的引用 currentThread()

publicstatic Thread.currentThread();  //返回当前线程对象的引用

2.3 休眠当前线程 sleep()

那个线程调用该方法就会进入休眠状态(阻塞),该进程暂时不参加系统的调度。该方法会抛出InterruptedException 异常

public static void sleep(long millis) throws InterruptedException

休眠当前线程 millis毫秒

public static void sleep(long millis, int nanos) throwsInterruptedException

可以更高精度的休眠


2.3 终止一个线程

一个线程启动之后,进入工作状态,就会按照我们设计的程序功能去执行,没有执行完毕也不会无缘无故的结束掉线程,以上述qq 视频通话为例, 打qq 视频通话,需要我们手动启动qq 视频通话,或者好友打来视频电话,这涉及到线程的启动(调用 start () 方法)。

如果我们想要结束掉视频通话,一般情况下有两种方法

就需要手动点击挂断,通话双方都可,意思就是线程可以主动的结束(我挂断),也可以被动的结束(好友挂断),无论是是挂断电话,线程都会结束。

无可抗因素,例如,手机断网,当我们手机没有网络支持,通话自然而然结束,或者是网络特别卡顿,也有可能结束掉线程,再或者是手机内存不够,系统无法继续为qq 提供内存资源使其运行,会强制中止 qq 的进程,一般是直接干掉进程(进程是操作系统分配资源的基本单位,进程包含线程,多线程共享进程资源)。

那我们java 代码在没有 (bug)的情况下如何终止进程,常见的有两种处理方法:

1. 共享标记来进行沟通
2. 调用 interrupt() 方法来通知线程该结束了

2.2.1 共享标记

publicclassDemo1 {privatestatic boolean flag = true; //共享标记
​publicstaticvoidmain(String[] args) throws InterruptedException {Thread t = newThread(() -> { //采用 lambda表达式创建线程对象while(flag) { // 使用共享标记可以由其他线程中止本线程try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程 t 执行");}});
​t.start(); // 启动线程,从启动开始就有两个线程流参与 CPU 的调度执行
​System.out.println("主线程 main 一秒后中止 t 线程");Thread.sleep(1000); //线程休眠一秒后再被CPU调度执行flag = false;System.out.println("t 线程已被中止");}
}

我们定义一个boolean类型 的成员变量 flag 用于条件判断终止线程,条件判断然后 return 、抛异常都可以。

运行结果:

运行结果有些意外,为什么当 main 线程中打印了 t 线程已被中止, 最后线程 t还打印了一个 线程 t 执行呢? 这个问题与系统的调度有一定的关系,两个线程并发执行,可能是由一个 cpu 核心处理,那么这两个线程就在 cpu 上切换执行,完全有可能,t 线程已经完成了第五次的条件判断,还没来的及打印, cpu 就执行main 线程 修改flag = false,然后打印,此时再切换为 t 线程 ,继续打印,再从 flag 读取 boolean 值进行条件判断就不符合条件了,当然 系统怎么调度的的线程,执行顺序是无序的,会有多种可能,而且 线程可以迸发执行,共享一个控制台的话,打印是必须得分个先后得,所以这种情况是正常得。

关于将 flag 设置为成员变量的问题:

那能不能将 flag 定义在 main() 方法内部, 线程 t 能不能访问到 flag 呢, 答案可以的。**

但是这里报错了,原因是:lambda表达式中使用的变量应该是final或有效final意思就是只能使用不发生改变的属性,如果我们 main 中只定义 flag = true; 并不对 flag 值进行修改,那么 lambda表达式中就可以访问到 flag 。

以上代码大致可以理解一下Java 代码线程终止线程的一种方式,写的有些简陋可能会涉及到线程安全的问题,这个篇博客在叙述。


2.2.2 调用 interrupt() 方法

刚刚采用的 共享标记的方法终止线程,共享标记需要我们手动的创建, interrupt() 方法是 Thread 类内置的一个方法,方法内部提供一个标志位,所以我们只需要调用该方法就可以实现终止线程的效果。

interrupt() 方法对调用线程设置标志位

使用 Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 判断线程是否创建了标志位

Thread.currentThread() : 返回对当前正在执行的线程对象的引用,针对于该线程判断是否创建了标志位

Thread 内部包含了一个 boolean 类型的变量作为线程是否被中断的标记

方法

说明

public void interrupt()

中断对象关联的线程,如果线程正在阻塞,则以异常方式通知,否则设置标志位

public static boolean interrupted()

判断当前线程的中断标志位是否设置,调用后清除标志位

public boolean isInterrupted()

判断对象关联的线程的标志位是否设置,调用后不清除标志位

我们使用 isInterrupted() 方法来判断是否设置了标志位(没有是 false),用interrupt() 方法进行标志位设置 true。

publicclassDemo2 {publicstaticvoidmain(String[] args) throws InterruptedException {
​Thread t = newThread(() -> { //采用 lambda表达式创建线程对象while(!Thread.currentThread().isInterrupted()) { //isInterrupted() 判断是否设置了标志位//!Thread.interrupted();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程 t 执行");}});
​t.start(); // 启动线程,从启动开始就有两个线程流参与 CPU 的调度执行
​System.out.println("主线程 main 3秒后中止 t 线程");Thread.sleep(3000); //线程休眠一秒后再被CPU调度执行t.interrupt(); // 设置把标志位,并将标志设置为true;}
}

Thread 接收到的是否有标志位通知有两种情况:

如果线程是因为 调用了sleep、join 等方法的原因阻塞(只要是阻塞,阻塞可以看作线程暂时不参加 CPU 的调度了),然后 t. interrupt() 方法设置标志,那么会通过抛出 InterruptedException 异常的形式通知,将线程唤醒,此处博主使用 sleep() 使得 t 线程休眠(阻塞一秒),主线程(main)调用方法设置标志后线程被强制唤醒,sleep() 会将标志位置为空 (标志位置为 false),意思就是相当于没设置标志,isInterrupted() 方法检查没有标志位,返回 false, 然后方法前面 !(非),结果返回 true, 线程不会终止。
当抛出 InterruptedException 异常的时候, 要不要结束线程取决于 catch 中代码的写法.,可以选择忽略这个异常(博主这里直接将异常抛出,所以标志位就被清空了), 也可跳出循环结束线程(break)。

没有阻塞等特殊情况,有两种方式判断是否存在标志位:

1)Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志 (清除后返回false)*
2)Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志

那么博主这段代码明显是第一种方式,设置一个标志位也是一波三折,看看运行结果:

抛出异常后 t 线程继续执行,说明抛出异常后,标志位被清除了,t 线程是循环一次sleep 阻塞一秒嘛,所以打印了两个结果,第三秒,主线程给 t 线程设置标志位(本意结束 t 线程),结果直接唤醒 阻塞中的 t 线程,从sleep 状态被唤醒后,sleep 将 isInterrupted() 的标志位清空,导致循环无法结束。
阻塞状态被设置标志位唤醒,将标志位清空的目的也是为了线程对何时结束有一个灵活的掌控, 如果上述状态我们对 sleep 进行异常处理 carch 里面添加break; 或者是 return; 都是可以的比较灵活。
调用 interrupt() 方法终止线程本质上还是设置标志位,不是说直接将线程干掉,而是程序通过标志位的信息可以进行终止线程的操作。

两个人打qq 视频电话,你不挂断,我也不挂断,那就一直死循环,挂断就相当于对这个循环按 break; 循环结束,如果该线程没有什么其他程序要执行的话启动周期也结束了。


2.3 join() 等待一个线程

等待一个线程,预设一个场景:

在只有一个厕所的情况下,李四只有等待张三(线程)执行完毕后才能上厕所(被调度),期间李四只能是耐心等待,也不能干其他的事。

同一进程下,多线程的调度是并发执行(CPU 来回切换执行线程),操作系统对线程的调度是无序的,每个线程被执行的时间也是未知的,无法判断线程之间的执行的先后顺序,那么使用 join 方法就可以指定那个线程等待那个线程执行完毕。

publicstaticvoidmain(String[] args) throws InterruptedException {Thread t = newThread( () -> {for (int i = 0; i < 5; i++) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程 t 执行");}});
​t.start(); //启动线程 t
​for (int i = 0; i < 5; i++) {Thread.sleep(1000);System.out.println("主线程 main 执行");}}

运行打印结果有时候 main 线程前,有时候 t 线程在前,这也说体现了线程的调度是无序的这个概念,添加 sleep函数的目的就是使得线程休眠一秒再执行,因为CPU 的执行速度很快,数据量小无法观察到这种并发调度的状态。

假设现在我们想让 main 主线程等待 t 线程执行完毕后再执行 自身的操作,就可以使用 join 方法。

很明显,使用 join 方法后线程的调度是有序的,但是此时 两个线程不再是并发执行,而是串行执行了, 在main 线程中 调用了 t. join 方法,意思就是 让main 线程等待 线程 t 执行完毕后,再往下执行, 谁调用,谁等待,等待的一方,直接进入 Blocked 阻塞状态,阻塞可以看作线程暂时不参加 CPU 的调度执行。

main 线程调用 t.join 的时候,如果 t 正在运行,此时 main 线程直接进入阻塞态,直到 t 线程执行完毕(run 方法执行完了),main 线程才会解除阻塞,继续参与系统调度,CPU 执行。

如果 t 线程一直在执行,那么 main 线程就会一直处于阻塞状态,这谁能忍,所以 join 还有另一个重载后的方法,可以在调用 join 时提供一个最大等待时间的参数,超出等待时间 main 线程也可以解除阻塞态。

方法

说明

public void join()

等待线程结束

public void join(long millis)

等待线程结束,最多等 millis 毫秒

public void join(long millis, int nanos)

同理,更高精度


至此,Java Thread 类及常用方法属性 博主已经分享完了,希望对大家有所帮助,如有不妥之处欢迎批评指正。

本期收录于博主的专栏——JavaEE,适用于编程初学者,感兴趣的朋友们可以订阅,查看其它“JavaEE基础知识”。

下期预告:线程的状态及线程安全相关问题

感谢每一个观看本篇文章的朋友,更多精彩敬请期待:保护小周ღ *★,°*:.☆( ̄▽ ̄)/$:*.°★* ‘

相关文章:

【JavaEE】Thread 类及常用方法

一、Thread 类Thread 类我们可以理解为是 java 用于管理线程的一个类&#xff0c;里面封装了操作系统提供的线程管理这一方面的 API &#xff08;Thread 是优化后的结果&#xff09;, Java 代码创建的每一个线程&#xff0c;可以理解为为 Thread 实例化的对象&#xff0c;Threa…...

C语言数据结构初阶(7)----队列

CSDN的uu们&#xff0c;大家好。这里是C语言数据结构的第七讲。 目标&#xff1a;前路坎坷&#xff0c;披荆斩棘&#xff0c;扶摇直上。 博客主页&#xff1a;姬如祎队列的基础知识队列&#xff08;queue&#xff09;是只允许在一端进行插入操作&#xff0c;而在另一端进行删除…...

代码随想录二刷 day01 | 704. 二分查找 27. 移除元素 977. 有序数组的平方

代码随想录二刷day01704. 二分查找27. 移除元素977. 有序数组的平方704. 二分查找 题目链接 做这种题最好现在纸上写一写&#xff0c;如果在大脑中想&#xff0c;可能一会就晕了。 二刷的时候发现了一个新的知识点 即&#xff1a; >>的作用 二分法第二种写法&#xff1a…...

Linux 终端、进程组、会话、守护进程

文章目录一、终端概念终端概念控制终端二、进程组概念进程组概述进程组相关 API会话会话概念会话相关 API创建会话注意事项守护进程守护进程介绍守护进程模型守护进程参考代码守护进程相关 API参考文章一、终端概念 终端概念 1、终端&#xff08;Terminal&#xff09; 终端是…...

你是否有潜质成为谷歌开发者专家?加入 GDE 成长计划,释放潜力!

谷歌开发者专家 (Google Developer Experts&#xff0c;GDE)&#xff0c;又称谷歌开发者专家项目&#xff0c;是由一群经验丰富的技术专家、具有社交影响力的开发者和思想领袖组成的全球性社区。通过在各项活动演讲以及各个平台上发布优质内容来积极助力开发者、企业和技术社区…...

安全防御之防火墙篇(二)

目录 1.防火墙如何处理双通道协议&#xff1f; 2.防火墙如何处理NAT&#xff1f; 3.防火墙支持哪些NAT技术&#xff0c;主要应用的场景是什么&#xff1f; 4.当内网PC通过公网域名解析访问内网服务器的时候&#xff0c;会存在什么问题&#xff0c;如何解决&#xff1f;请详细…...

设计必备,5个png免抠素材网站,建议收藏

做设计、PPT都需要用到大量的免抠素材&#xff0c;职场中熟练使用Photoshop的人毕竟是少数&#xff0c;也很少有人愿意花费时间去精细抠图。那这5个免抠素材网站一定要收藏好&#xff0c;可以有效帮你节省时间&#xff0c;提高工作效率。 1、菜鸟图库 https://www.sucai999.co…...

shell 脚本expect

expect 是什么 expect - programmed dialogue with interactive programs&#xff08;与互动程序进行程序对话&#xff09; 定义脚本执行的 shell #!/usr/bin/expect -f 定义的是执行 expect 可执行文件的链接路径&#xff08;或真实路径&#xff09;&#xff0c;功能类似于bas…...

第十九天 Maven总结

目录 Maven 1. 前言 2. 概述 2.1 介绍 2.2 安装 3. IDEA集成Maven 3.1 集成Maven环境 3.2 创建Maven项目 3.3 Maven坐标详解 3.4 导入maven项目 4. 依赖管理 4.1 依赖配置 4.2 依赖传递 4.3 依赖范围 4.4 生命周期 4.5 插件 Maven 1. 前言 1). 什么是Maven? …...

ESP8266-NodeMCU开发板-------开发板介绍(1)

目录 认识ESP8266-NodeMCU开发板​编辑 GPIO编号与NodeMCU开发板引脚名的区别&#xff1a; ESP8266 GPIO编号与NodeMCU开发板引脚名的对应关系 可用引脚 电压电流限制 特殊引脚情况说明 上拉电阻/下拉电阻 模拟输入 通讯 认识ESP8266-NodeMCU开发板 初识NodeMCU开发板 (第1章-第…...

【测试开发篇3】软件测试的常用概念

目录 一、软件测试的生命周期(5个步骤) ①需求分析(两个角度) 用户角度&#xff1a; 开发人员的角度&#xff1a; ②测试计划 ③测试设计、测试开发 ④执行测试 ⑤测试评估 二、软件测试贯穿项目的整个生命周期的体现 需求分析阶段 计划阶段 设计阶段 编码阶段 …...

javaEE初阶 — JavaScript WebAPI

文章目录什么是 DOMDOM 树获取元素1. querySelector2. querySelectorAll事件1. 事件三要素2. 代码案例获取 / 修改元素内容1. innerHTML获取 / 修改元素属性获取 / 修改表单元素属性获取 / 修改样式属性1. 修改内联样式&#xff08;修改 style 属性的值&#xff09;2. 修改元素…...

UE实现地面动态交互效果

文章目录 1.实现目标2.实现过程2.1 SphereMask2.2 材质实现2.3 位置更新3.参考资料1.实现目标 基于SphereMask材质节点实现人物在地面一定范围内的颜色高亮效果。 2.实现过程 实现原理是首先通过,SphereMask材质节点更具计算输出Mask值,其中在球体半径内的输入1,在外部的则…...

如何用自己的数据训练YOLOv5

如何训练YOLOv5 1. Clone the YOLOv5 repository and install dependencies: git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txt2. 整理数据&#xff0c;使其适配YOLO训练 Step1&#xff1a;Organize your dataset in the fo…...

【基础算法】数组相关题目

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招算法的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于代码随想录进行的&#xff0c;每个算法代码参考leetcode高赞回答和…...

MatBox—基于PyQt快速入门matplotlib的教程库

MatBox—基于PyQt快速入门matplotlib的教程库 __ __ _ _ _ _ _ _ _______ _ _ _ | \/ | | | | | | | | |(_)| | |__ __| | | (_) | || \ / | __ _ |…...

go channel使用

go语言中有一句名言&#xff1a; 不要通过共享内存来通信&#xff0c;而应该通过通信来共享内存。 channel实现了协程间的互相通信。 目录 一、channel声明 二、向channel发送数据 三、从channel读取数据 1. i, ok : <-c 2. for i : range c&#xff08;常用&#xff09…...

5. QtDesignStudio中的3D场景

1. 说明&#xff1a; 三维渲染开发是Design Studio的重要功能&#xff0c;且操作方便&#xff0c;设计效率非常高&#xff0c;主要用到的控件是 View3D ,可以在3D窗口中用鼠标对模型直接进行旋转/移动/缩放等操作&#xff0c;也可以为模型设置各种动画&#xff0c;执行一系列的…...

人工智能的几个研究方向

人工智能主要研究内容是&#xff1a;分布式人工智能与多智能主体系统、人工思维模型、知识系统、知识发现与数据挖掘、遗传与演化计算、人工生命、人工智能应用等等。 其中热门研究有以下几种。 一、计算机视觉 就包括图像识别&#xff0c;视频识别&#xff0c;具体应用有人…...

软件测试 - 常见的开发模型和测试模型

1.瀑布模型优点强调开发的阶段性, 强调早期计划及需求调查, 强调产品测试;缺点1. 由于瀑布模型是一种线型结构的模型, 也就意味着前一个阶段结束, 后一个阶段才能开始, 这就导致了风险往往会迟至后期的测试阶段才显露, 因而失去了及早纠正的机会.2. 瀑布模型中测试被后置, 导致…...

从零开始的机械臂yolov5抓取gazebo仿真(四)

Moveit与Gazebo联合仿真 上一篇博客已经将moveit!配置完毕&#xff0c;然而想要让moveit!控制gazebo中的机械臂&#xff0c;还需要进行一些接口的配置。现在我们有的功能包为sunday_description、sunday_moveit_config这两个功能包。且已经配置好xacro文件&#xff0c;本篇内容…...

C++修炼之筑基期第一层——认识类与对象

文章目录&#x1f337;专栏导读&#x1f337;什么是面向对象&#xff1f;&#x1f337;类的引入&#x1f337;什么是类&#x1f337;类的定义方式&#x1f337;类的访问限定符与封装&#x1f33a;访问限定符&#x1f33a;封装&#x1f337;类的作用域&#x1f337;类的实例化&a…...

IT 运营监控工具

在技术复杂性日益增加、业务竞争激烈的挑战以及消费者对服务中断接受度降低的世界中&#xff0c;IT 运营效率已成为增长、利润和成功的关键。IT 宕机的影响在几十年前威胁较小&#xff0c;现在意味着价值数百万美元的损失&#xff0c;有时甚至会损失各种规模的组织的业务和声誉…...

java线程之Thread类的基本用法

Thread类的基本用法1. Thread类的构造方法2. Thread的几个常见属性常见属性线程中断等待一个线程小鱼在上一篇博客详细的讲解了如何创建线程,java使用Thread类来创建多线程,但是对于好多没有相关经验的人来说,比较不容易理解的地方在于操作系统调度的执行过程. 我们通过下面代码…...

【js】多分支语句练习(2)

个人名片&#xff1a; &#x1f60a;作者简介&#xff1a;一名大一在校生&#xff0c;web前端开发专业 &#x1f921; 个人主页&#xff1a;python学不会123 &#x1f43c;座右铭&#xff1a;懒惰受到的惩罚不仅仅是自己的失败&#xff0c;还有别人的成功。 &#x1f385;**学习…...

Redis与MySQL的双写一致性问题

Redis与MySQL的双写一致性问题更新缓存&#xff1f; 删除缓存&#xff1f;先更新缓存再更新数据库先更新数据库&#xff0c;再更新缓存先删除缓存再更新数据库先更新数据库&#xff0c;再删除缓存解决方案1. 重试2. 异步重试2.1 使用消息队列实现重试2.2 Binlog实现异步重试删除…...

Java基础:笔试题

文章目录Java 基础题目1. 如下代码输出什么&#xff1f;2. 当输入为2的时候返回值是多少?3. 如下代码输出值为多少?4. 给出一个排序好的数组&#xff1a;{1,2,2,3,4,5,6,7,8,9} 和一个数&#xff0c;求数组中连续元素的和等于所给数的子数组解析第一题第二题第三题第四题方案…...

spring三级缓存以及@Async产生循环引用

spring三级缓存以及Async产生循环引用spring三级缓存介绍三级缓存解除循环引用原理源码对应1、获取A&#xff0c;从三级缓存中获取&#xff0c;没有获取到2、构造A&#xff0c;将A置入三级缓存构造A(创建A实例)置入缓存3、注入属性&#xff0c;构造B扫描缓存实例的相关信息注入…...

【洛谷刷题】蓝桥杯专题突破-深度优先搜索-dfs(5)

目录 写在前面&#xff1a; 题目&#xff1a;P2036 [COCI2008-2009#2] PERKET - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目描述&#xff1a; 输入格式&#xff1a; 输出格式&#xff1a; 输入样例&#xff1a; 输出样例&#xff1a; 解题思路&#xff1a; 代码…...

【Unity3D】Unity3D中在创建完项目后自动创建文件夹列表

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 随着项目开发的体量增大&#xff0c;要导入大量的素材、UI、模…...