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

Spring Boot进阶(60):5种判断线程池任务是否全部完成的方案 | 实用技巧分享!

 1. 前言🔥

        多线程编程在现代软件开发中非常常见且重要,而线程池是多线程编程的常用技术。在使用线程池时,通常需要判断线程池中的任务是否全部完成,以便决定程序继续执行的下一步操作。本文将介绍5种判断线程池任务是否全部完成的方案,帮助开发者解决这一问题。

        所以呢,你们打算怎么处理?这将又会是干货满满的一期,全程无尿点不废话只抓重点教,具有非常好的学习效果,拿好小板凳准备就坐!希望学习的过程中大家认真听好好学,学习的途中有任何不清楚或疑问的地方皆可评论区留言或私信,bug菌将第一时间给予解惑,那么废话不多说,直接开整!Fighting!! 

2. 环境说明🔥

本地的开发环境:

  • 开发工具:IDEA 2021.3
  • JDK版本: JDK 1.8
  • Spring Boot版本:2.3.1 RELEASE
  • Maven版本:3.8.2

3. 正文🔥 

3.1 需求分析

        前言提到采用线程池来并发处理多个sql查询,其实使用线程池不麻烦,麻烦的是你要通过什么方式去统计线程池中的任务都被执行,何为都执行完了?其实这也很理解,无非你就是要把握一个点,判断【计划执行任务数】是否等于【已完成任务数】即可,如果相等则说明线程池中的任务全被执行掉了,反之就是未执行完。

        那么你就朝着这个方向去思考,有那些方式可以算出【计划执行任务数】与【已完成任务数】这两个量值?

3.2 实现概述

        统计线程池中的任务是否被全执行完的方法其实有很多很多,我给大家举几个例子: 

  • 使用 getCompletedTaskCount() 统计出【已完成任务数】和使用Java线程池中的getTaskCount() 方法来获取【总任务数】,二者进行对比即可。
  • 使用 FutureTask对象 ,等待所有任务都执行完,线程池的任务就都执行完了。
  • 使用 CountDownLatch对象 或 CyclicBarrier对象,等待所有线程都执行完之后,再执行后续流程,计数。
  • 使用isTerminated() 方法。利用线程池的终止状态(TERMINATED)来判断线程池的任务是否已经全部执行完,但想要线程池的状态发生改变,就需要调用线程池的 shutdown() 方法,不然线程池一直会处于 RUNNING 运行状态,那就没办法使用终止状态来判断任务是否已经全部执行完了,shutdown() 方法是启动线程池有序关闭的方法,它在完全关闭之前会执行完之前所有已经提交的任务,并且不会再接受任何新任务。当线程池中的所有任务都执行完之后,线程池就进入了终止状态,调用 isTerminated() 方法返回的结果就是 true 了,以这点作为依据来判断即可。
  • ...

        如果你有其他的点子,欢迎评论区交流学习。

 3.3 实现方案

3.3.1 统计完成已完成任务数

        这里通过使用getCompletedTaskCount()和getTaskCount() 方法分别统计出统计出【已完成任务数】和【总任务数】,如果相等则说明线程池的任务执行完了,否则既未执行完。

示例代码如下:

    //校验计划执行任务数 ?= 已完成任务数private static void isCompletedByTaskCount(ThreadPoolExecutor threadPool) {while (threadPool.getTaskCount() != threadPool.getCompletedTaskCount()) {}}

具体演示代码如下:

package com.example.demo.component.threadPool;import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class CountThreadTask {//创建一个最大线程数100的线程池private static ExecutorService es =new ThreadPoolExecutor(3, 100, 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(100));public static void main(String[] args) throws Exception {for (int i = 1; i <= 10; i++) {int finalI = i;es.execute(() -> { //提交执行System.out.println("线程" + finalI + "执行完成!");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}});}ThreadPoolExecutor threadPool = ((ThreadPoolExecutor) es);System.out.println("线程池任务总数量:"+threadPool.getTaskCount());System.out.println("---------线程池开始执行-----------");while (true) {if (threadPool.getTaskCount() == threadPool.getCompletedTaskCount()) {System.out.println("---------线程池执行完了-----------");break;}//间隔2s查询一次Thread.sleep(2000);System.out.println("线程池还未执行完,敬请等待!已完成的任务数量:"+threadPool.getCompletedTaskCount());}}}

执行main函数,结果控制台打印示例如下,仅供参考:

方法说明及拓展:

  • getTaskCount():返回线程池计划执行的任务总数。注意:由于任务和线程的状态可能在计算过程中动态变化,因此该方法返回值只是一个近似值,不是精准的。
  • getCompletedTaskCount():返回线程池中已完成的任务数,注意:跟getTaskCount()方法一致,该方法返回值也是一个近似值。
  • getPoolSize():返回线程池当前的线程数量。
  • getActiveCount():返回当前线程池中正在执行任务的线程数量。

方式总结:

        由于getTaskCount() 与 getCompletedTaskCount()方法返回值都是一个近似值而不是精确值,固结果可能有一定的偏差,这也是该方式的一大缺点。

3.3.2 使用 FutureTask 

        与方式1不同的是,FutrueTask 可以弥补它的弊端,使用它可以精准获取任务结果,调用每个 FutrueTask 对象的 get() 方法就是等待该任务执行完,如下代码所示:

package com.example.demo.component.threadPool;import java.util.concurrent.*;/*** 使用 FutrueTask 等待线程池执行完全部任务*/
public class FutureTaskTask {//创建一个最大线程数100的线程池private static ExecutorService es =new ThreadPoolExecutor(4, 100, 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(100));public static void main(String[] args) throws ExecutionException, InterruptedException {// 创建任务1FutureTask<Integer> task1 = new FutureTask<>(() -> {System.out.println("---Task 1 开始执行---");Thread.sleep(2000);System.out.println("------Task 1 执行结束------");return 1;});// 创建任务2FutureTask<Integer> task2 = new FutureTask<>(() -> {System.out.println("---Task 2 开始执行---");Thread.sleep(3000);System.out.println("------Task 2 执行结束------");return 2;});// 创建任务3FutureTask<Integer> task3 = new FutureTask<>(() -> {System.out.println("---Task 3 开始执行---");Thread.sleep(1000);System.out.println("------Task 3 执行结束------");return 3;});// 创建任务4FutureTask<Integer> task4 = new FutureTask<>(() -> {System.out.println("---Task 4 开始执行---");Thread.sleep(500);System.out.println("------Task 4 执行结束------");return 4;});// 提交4个任务给线程池es.submit(task1);es.submit(task2);es.submit(task3);es.submit(task4);// 等待所有任务执行完毕task1.get();task2.get();task3.get();task4.get();//执行完毕System.out.println("线程池执行完了!");}
}

执行main函数,结果控制台打印示例如下,仅供参考:

3.3.3 使用CountDownLatch 

        CountDownLatch身为同步工具类,作用之一可协调多个线程之间的同步,或者说接通线程之间的通信(而不是互斥)。CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后再继续执行。其中,计数器初始值为全线程的数量,当每一个线程完成自己任务后,计数器的值就会自动减1;当计数器的值 = 0时,表示所有的线程都已经完成一些任务,然后在CountDownLatch上等待的线程就可以恢复执行接下来的任务。

        接下来给大家演示下,如何巧妙利用CountDownLatch达到统计线程池所有线程都被执行完的需求?请看示例代码:

package com.example.demo.component.threadPool;import java.util.concurrent.*;/*** 使用CountDownLatch*/
public class CountDownLatchTask {//创建一个最大线程数100的线程池private static ExecutorService es =new ThreadPoolExecutor(1, 100, 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(100));public static void main(String[] args) throws Exception {//计数器,判断线程是否执行结束//初始值为10CountDownLatch taskLatch = new CountDownLatch(10);for (int i = 0; i < 10; i++) {es.execute(() -> { //提交执行taskLatch.countDown();System.out.println("当前计数器值为:" + taskLatch.getCount());try {//模拟线程执行方法,执行1sThread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}});}//当前线程阻塞,等待计数器置为0taskLatch.await();System.out.println("线程池执行完了!");}}

执行main函数,结果控制台打印示例如下,仅供参考:

方式总结:

        虽然使用CountDownLatch可达到统计线程是否被执行完,该方式使用起来代码简洁优雅,不需要对线程池进行操作。但由于CountDownLatch是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当CountDownLatch使用完毕后,它不能再次被使用。

3.3.4 使用CyclicBarrier 

        CyclicBarrier 和 CountDownLatch 类似,你可以把它理解为一个可以重复使用的循环计数器,CyclicBarrier 可调用 reset() 方法将自己重置到初始状态,这是与CountDownLatch不一样的特性,那具体如何使用CyclicBarrier达到统计线程池所有线程都被执行完的需求吧,具体实现代码如下,仅供参考:

package com.example.demo.component.threadPool;import java.util.Random;
import java.util.concurrent.*;/*** 使用CyclicBarrier*/
public class CyclicBarrierTask {//创建一个最大线程数100的线程池private static ExecutorService es =new ThreadPoolExecutor(5, 100, 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(100));public static void main(String[] args) throws InterruptedException {//任务总数final int taskCount = 5;//循环计数器CyclicBarrier cyclicBarrier = new CyclicBarrier(taskCount, new Runnable() {@Overridepublic void run() {// 线程池执行完System.out.println("---------线程池执行完了-----------");}});// 添加任务for (int i = 0; i < taskCount; i++) {final int finalI = i;es.submit(new Runnable() {@Overridepublic void run() {try {//随机休眠1-4秒TimeUnit.SECONDS.sleep(new Random().nextInt(5));System.out.println("任务" + finalI + "执行完成");// 线程执行完cyclicBarrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}}});}}
}

执行main函数,结果控制台打印示例如下,仅供参考:

3.3.5 使用isTerminated()

        使用线程池的 isTerminated() 方法,在执行 shutdown() 进行线程池的关闭后, 隔间调用isTerminated()判断线程池中的所有任务是否已经完成即可。那具体如何使用 isTerminated() 方法达到统计线程池所有线程都被执行完的需求吧,具体实现代码如下,仅供参考:

package com.example.demo.component.threadPool;import java.util.concurrent.*;/*** 使用isTerminated()*/
public class IsTerminatedTask {//创建一个最大线程数100的线程池private static ExecutorService es =new ThreadPoolExecutor(4, 100, 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(100));public static void main(String[] args) throws Exception {for (int i = 1; i <= 10; i++) {int finalI = i;es.execute(() -> { //提交执行System.out.println("线程" + finalI + "执行完成!");try {//模拟线程执行过程Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}});}//关闭线程池es.shutdown();//隔间1s判断是否执行完了,如果所有任务在关闭后完成,返回true。while (!es.isTerminated()) {Thread.sleep(1000);}System.out.println("---------线程池执行完了-----------");}
}

执行main函数,结果控制台打印示例如下,仅供参考:

在上述代码演示中,在主线程中进行循环判断,全部任务是否已经完成。 

拓展:

  • shutdown() :对线程池进行有序关闭。调用该方法后,线程池将不再接受新的任务,但会继续执行已提交的任务。如果线程池已经处于关闭状态,则对该方法的调用没有额外的作用。
  • isTerminated() :判断线程池中的所有任务是否在关闭后完成。只有在调用了shutdown()或shutdownNow()方法后,所有任务执行完毕,才会返回true。需要注意的是,在调用shutdown()之前调用isTerminated()方法始终返回false值的。

3.4 小结

        如上,我总共诺列了五种解决思路,小伙伴在面对该场景时,猜想第一感觉想到的会是方式1跟方式5吧,但是这五种方式,实现思路上各有优劣,如下bug菌就简单给同学们分析下其中的关系利弊,仅供参考。

3.4.1 使用getCompletedTaskCount()和getTaskCount() 方法

优点:使用它可不需要进行线程池的关闭,避免了创建线程池及销毁所带来的内存开销。

缺点:使用它两方法返回的都是一个近似值,而且进行线程判断局限很大,要保证在循环判断过程中没有产生新的任务,否则该方式就统计失效了。

3.4.2 使用 FutureTask

优点:使用其方法就是主打一个精确值,使用简单优雅,不需要对线程池有任何的操作。

缺点:每个提交给线程池的任务都会关联一个FutureTask对象,这就可能会损耗额外的内存开销。如果需要处理大量的任务,可能会占用较大的内存资源。

3.4.3 使用CountDownLatch 

优点:使用简单优雅,不需要对线程池有任何的操作。

缺点:使用CountDownLatch 计数器只能使用一次,CountDownLatch 创建之后不能重复使用,而且需要提前知道线程的数量,性能较差,还需要在线程代码块内加上异常判断,否则在 countDown()之前发生异常而没有处理,就会导致主线程永远阻塞在 await 。

3.4.4 使用CyclicBarrier 

优点:使用简单优雅,计数器可重置进行重复使用。

缺点:使用难度较高。相比CountDownLatch而言,CyclicBarrier 无论从设计还是使用,复杂度都高于CountDownLatch,相比 CountDownLatch 而言它的优点就是可以重复使用。

3.4.5 使用isTerminated()

优点:使用简单优雅。

缺点:使用场景受限,需要shutdown()关闭线程池。因为日常使用是会将线程池注入到Spring容器里,然后各个组件中都统一用同一个线程池,不能直接关闭线程池。

... ...

        以上提供了五种不同的思路对其进行求解,且分析了这五种方式的使用优劣,希望对同学们有所帮助。如果有小伙伴还有其他的奇思妙想,欢迎评论区大胆交流,一起学习。

4. 热文推荐🔥

滴~如下推荐【Spring Boot 进阶篇】的学习大纲,请小伙伴们注意查收。

Spring Boot进阶(01):Spring Boot 集成 Redis,实现缓存自由

Spring Boot进阶(02):使用Validation进行参数校验

Spring Boot进阶(03):如何使用MyBatis-Plus实现字段的自动填充

Spring Boot进阶(04):如何使用MyBatis-Plus快速实现自定义sql分页

Spring Boot进阶(05):Spring Boot 整合RabbitMq,实现消息队列服务

Spring Boot进阶(06):Windows10系统搭建 RabbitMq Server 服务端

Spring Boot进阶(07):集成EasyPoi,实现Excel/Word的导入导出

Spring Boot进阶(08):集成EasyPoi,实现Excel/Word携带图片导出

Spring Boot进阶(09):集成EasyPoi,实现Excel文件多sheet导入导出

Spring Boot进阶(10):集成EasyPoi,实现Excel模板导出成PDF文件

Spring Boot进阶(11):Spring Boot 如何实现纯文本转成.csv格式文件?

Spring Boot进阶(12):Spring Boot 如何获取Excel sheet页的数量?

Spring Boot进阶(13):Spring Boot 如何获取@ApiModelProperty(value = “序列号“, name = “uuid“)中的value值name值?

Spring Boot进阶(14):Spring Boot 如何手动连接库并获取指定表结构?一文教会你

Spring Boot进阶(15):根据数据库连接信息指定分页查询表结构信息

Spring Boot进阶(16):Spring Boot 如何通过Redis实现手机号验证码功能?

Spring Boot进阶(17):Spring Boot如何在swagger2中配置header请求头等参数信息

Spring Boot进阶(18):SpringBoot如何使用@Scheduled创建定时任务?

Spring Boot进阶(19):Spring Boot 整合ElasticSearch

Spring Boot进阶(20):配置Jetty容器

Spring Boot进阶(21):配置Undertow容器

Spring Boot进阶(22):Tomcat与Undertow容器性能对比分析

Spring Boot进阶(23):实现文件上传

Spring Boot进阶(24):如何快速实现多文件上传?

Spring Boot进阶(25):文件上传的单元测试怎么写?

Spring Boot进阶(26):Mybatis 中 resultType、resultMap详解及实战教学

Spring Boot进阶(27):Spring Boot 整合 kafka(环境搭建+演示)

Spring Boot进阶(28):Jar包Linux后台启动部署及滚动日志查看,日志输出至实体文件保存

Spring Boot进阶(29):如何正确使用@PathVariable,@RequestParam、@RequestBody等注解?不会我教你,结合Postman演示

Spring Boot进阶(30):@RestController和@Controller 注解使用区别,实战演示

...

5. 文末🔥

        如果想系统性的学习Spring Boot,小伙伴们直接订阅bug菌专门为大家创建的Spring Boot专栏《滚雪球学Spring Boot》从入门到精通,从无到有,从零到一!以知识点+实例+项目的学习模式由浅入深对Spring Boot框架进行学习&使用。

        如果你有一定的基础却又想精进Spring Boot,那么《Spring Boot进阶实战》将会是你的最好的选择;此栏进行知识点+实例+项目的学习方式全面深入框架剖析及各种高阶玩法,励志打造全网最全最新springboot学习专栏,投资学习自己性价比最高。

        本文涉及所有源代码,均已上传至github开源,供同学们一对一参考,GitHub,同时,原创开源不易,欢迎给个star🌟,想体验下被加Star的感jio,非常感谢 ❗

       我是bug菌,一名想走👣出大山改变命运的程序猿。接下来的路还很长,都等待着我们去突破、去挑战。来吧,小伙伴们,我们一起加油!未来皆可期,fighting!

关注公众号,获取最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等硬核资源

相关文章:

Spring Boot进阶(60):5种判断线程池任务是否全部完成的方案 | 实用技巧分享!

1. 前言&#x1f525; 多线程编程在现代软件开发中非常常见且重要&#xff0c;而线程池是多线程编程的常用技术。在使用线程池时&#xff0c;通常需要判断线程池中的任务是否全部完成&#xff0c;以便决定程序继续执行的下一步操作。本文将介绍5种判断线程池任务是否全部完成的…...

Git相关介绍和操作

Git 是一个版本控制系统&#xff0c;它可以记录代码的变更历史&#xff0c;并允许多人协同开发。下面是 Git 的基本概念和使用方式&#xff1a; 仓库&#xff08;Repository&#xff09;&#xff1a;Git 仓库用于存储代码的版本历史&#xff0c;包括代码变更、注释、作者、时间…...

IDEA配置热启动

1.背景 开发过程中&#xff0c;当写完一个功能我们需要运行应用程序测试&#xff0c;可能这个小功能中存在多个小bug&#xff0c;我们需要改正后重启服务器&#xff0c;这无形之中拖慢了开发的速度增加了开发时间&#xff0c;SpringBoot提供了spring-boot-devtools&#xff0c;…...

【附安装包】Fireworks CS6安装教程

软件下载 软件&#xff1a;Fireworks版本&#xff1a;CS6语言&#xff1a;简体中文大小&#xff1a;165.87M安装环境&#xff1a;Win11/Win10/Win8/Win7硬件要求&#xff1a;CPU2.0GHz 内存4G(或更高&#xff09;下载通道①百度网盘丨下载链接&#xff1a;https://pan.baidu.c…...

深度学习-4-二维目标检测-YOLOv3理论模型

单阶段目标检测模型YOLOv3 R-CNN系列算法需要先产生候选区域&#xff0c;再对候选区域做分类和位置坐标的预测&#xff0c;这类算法被称为两阶段目标检测算法。近几年&#xff0c;很多研究人员相继提出一系列单阶段的检测算法&#xff0c;只需要一个网络即可同时产生候选区域并…...

通俗理解DDPM到Stable Diffusion原理

代码1&#xff1a;stabel diffusion 代码库代码2&#xff1a;diffusers 代码库论文&#xff1a;High-Resolution Image Synthesis with Latent Diffusion Models模型权重&#xff1a;runwayml/stable-diffusion-v1-5 文章目录 1. DDPM的通俗理解1.1 DDPM的目的1.2 扩散过程1.3 …...

如何基于自己训练的Yolov5权重,结合DeepSort实现目标跟踪

网上有很多相关不错的操作demo&#xff0c;但自己在训练过程仍然遇到不少疑惑。因此&#xff0c;我这总结一下操作过程中所解决的问题。 1、deepsort的训练集是否必须基于逐帧视频&#xff1f; 我经过尝试&#xff0c;发现非连续性的图像仍可以作为训练集。一个实例&#xff0…...

C#_委托详解

委托是什么&#xff1f; 字面理解&#xff1a;例如A要建一栋别墅&#xff0c;找到B建筑施工队&#xff0c;请B来建筑别墅。 委托类型规定方法的签名&#xff08;方法类型&#xff09;&#xff1a;返回值类型、参数类型、个数、顺序。 委托变量可以用来存储方法的引用&#x…...

R包开发-2.2:在RStudio中使用Rcpp制作R-Package(更新于2023.8.23)

目录 4-添加C函数 5-编辑元数据 6-启用Roxygen&#xff0c;执行文档化。 7-单元测试 8-在自己的计算机上安装R包&#xff1a; 9-程序发布 参考&#xff1a; 为什么要写这篇文章的更新日期&#xff1f;因为R语言发展很快&#xff0c;很多函数或者方式&#xff0c;现在可以使…...

基于数据湖的多流拼接方案-HUDI实操篇

目录 一、前情提要 二、代码Demo &#xff08;一&#xff09;多写问题 &#xff08;二&#xff09;如果要两个流写一个表&#xff0c;这种情况怎么处理&#xff1f; &#xff08;三&#xff09;测试结果 三、后序 一、前情提要 基于数据湖对两条实时流进行拼接&#xff0…...

Spring MVC 四:Context层级

这一节我们来回答上篇文章中避而不谈的有关什么是RootApplicationContext的问题。 这就需要引入Spring MVC的有关Context Hierarchy的问题。Context Hierarchy意思就是Context层级&#xff0c;既然说到Context层级&#xff0c;说明在Spring MVC项目中&#xff0c;可能存在不止…...

【C++ 学习 ⑱】- 多态(上)

目录 一、多态的概念和虚函数 1.1 - 用基类指针指向派生类对象 1.2 - 虚函数和虚函数的重写 1.3 - 多态构成的条件 1.4 - 多态的应用场景 二、协变和如何析构派生类对象 2.1 - 协变 2.2 - 如何析构派生类对象 三、C11 的 override 和 final 关键字 一、多态的概念和虚…...

合宙Air724UG LuatOS-Air LVGL API控件--进度条 (Bar)

进度条 (Bar) Bar 是进度条&#xff0c;可以用来显示数值&#xff0c;加载进度。 示例代码 – 创建进度条 bar lvgl.bar_create(lvgl.scr_act(), nil) – 设置尺寸 lvgl.obj_set_size(bar, 200, 20); – 设置位置居中 lvgl.obj_align(bar, NULL, lvgl.ALIGN_CENTER, 0, 0) …...

图神经网络与分子表征:番外——基组选择

学过高斯软件的人都知道&#xff0c;我们在撰写输入文件 gjf 时需要准备输入【泛函】和【基组】这两个关键词。 【泛函】敲定计算方法&#xff0c;【基组】则类似格点积分中的密度&#xff0c;与计算精度密切相关。 部分研究人员借用高斯中的一系列基组去包装输入几何信息&am…...

rabbitmq笔记-rabbitmq客户端开发使用

连接RabbitMQ 1.创建ConnectionFactory&#xff0c;给定参数ip地址&#xff0c;端口号&#xff0c;用户名和密码等 2.创建ConnectionFactory&#xff0c;使用uri方式实现&#xff0c;创建channel。 注意&#xff1a; Connection可以用来创建多个channel实例&#xff0c;但c…...

13.Oracle中nvl()与nvl2()函数详解

Oracle中nvl()与nvl2()函数详解&#xff1a; 函数nvl(expression1,expression2)根据参数1是否为null返回参数1或参数2的值&#xff1b; 函数nvl2(expression1,expression2,expression3)根据参数1是否为null返回参数2或参数3的值 1.nvl&#xff1a;根据参数1是否为null返回参数…...

设置某行被选中并滚动到改行

<el-table :data"tableDamItem" ref"singleTable" stripe style"width: 100%" height"250" highlight-current-row v-on:row-click"handleTableRow"></el-table>/*** 设置表格行被选中,并滚动到该行* param po…...

React钩子函数之useRef的基本使用

React钩子函数中的useRef是一个非常有用的工具&#xff0c;它可以用来获取DOM元素或者保存一些变量。在这篇文章中&#xff0c;我们将会讨论useRef的基本使用。 首先&#xff0c;我们需要知道useRef是如何工作的。它返回一个可变的ref对象&#xff0c;这个对象可以在组件的整个…...

无风扇迷你电脑信息与购买指南

本文将解释什么是无风扇迷你电脑&#xff0c;以及计算产品组合中你可以购买的一些不同的无风扇迷你电脑的信息指南。 无风扇迷你电脑是一种小型工业计算机&#xff0c;旨在处理复杂的工业工作负载。迷你电脑是通过散热器被动冷却可在各种类型的易失性环境中部署。无风扇微型计…...

比特币是怎么回事?

比特币是怎么回事&#xff1f; 一句话描述就是&#xff0c;初始化几个比特币&#xff0c;申请成为矿工组织&#xff0c;发生交易时抢单记账成功可以比特币奖励&#xff0c;随着比特币数量的增加&#xff0c;奖励越来越少。怎么记账成功呢&#xff0c;通过交易信息幸运数字哈希…...

vue3+ts+uniapp小程序端自定义日期选择器基于内置组件picker-view + 扩展组件 Popup 实现自定义日期选择及其他选择

vue3ts 基于内置组件picker-view 扩展组件 Popup 实现自定义日期选择及其他选择 vue3tsuniapp小程序端自定义日期选择器 1.先上效果图2.代码展示2.1 组件2.2 公共方法处理日期2.3 使用组件 3.注意事项3.1refSelectDialog3.1 backgroundColor"#fff" 圆角问题 自我记…...

Java进阶篇--泛型

前言 Java 泛型&#xff08;generics&#xff09;是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制&#xff0c;该机制允许程序员在编译时检测到非法的类型。它允许在定义类、接口和方法时使用类型参数。这种技术使得在编译期间可以使用任何类型&#xff0c;而…...

android framework之Applicataion启动流程分析

Application启动流程分析 启动方式一&#xff1a;通过Launcher启动app 启动方式二&#xff1a;在某一个app里启动第二个app的Activity. 以上两种方式均可触发app进程的启动。但无论哪种方式&#xff0c;最终通过通过调用AMS的startActivity()来启动application的。 根据上图…...

Linux Day10 ---Mybash

目录 一、Mybash介绍 1.1.mybash.c 打印函数 分割函数 命令函数 二、Mybash实现 2.1.打印函数 2.1.1需要使用到的功能函数 1.获取与当前用户关联的UID 2.获取与当前用户的相关信息---一个结构体&#xff08;passwd&#xff09; 3.获取主机信息 4.获取当前所处位置 5.给…...

Flask-Sockets和Flask-Login联合实现websocket的登录认证功能

flask_login 提供了一个方便的方式来管理用户会话。当你在 Flask 的 HTTP 视图中使用它时&#xff0c;你可以简单地使用 login_required 装饰器来确保用户已登录。 但是&#xff0c;flask_sockets 并没有直接与 flask_login 集成。如果你想在建立 WebSocket 连接时检查用户是否…...

东盟全面覆盖?长城战略部署核心区域市场,首个百万粉丝国产品牌

根据最新消息&#xff0c;长城汽车在东南亚地区取得了巨大的成功&#xff0c;成功进军了亚洲最大的汽车市场之一-印度尼西亚。这标志着长城汽车已经实现了东盟核心市场的全面覆盖&#xff0c;成为全球布局的重要一步。 在过去的几年里&#xff0c;长城汽车在东盟地区的市场布局…...

基于PHP的电脑商城系统

有需要请加文章底部Q哦 可远程调试 基于PHP的电脑商城系统 一 介绍 此电脑商城系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。用户可注册登录&#xff0c;购物下单&#xff0c;评论等。管理员登录后台对电脑商品&#xff0c;用户&#xff0c;订单&a…...

无客户端网络准入方案,为集成电路企业终端管理开启省事更省心模式

宁盾无客户端网络准入控制方案正在成为先进制造、高科技互联网企业等创新型客户的优选方案。创新型客户以技术密集型、研发人员占比高著称&#xff0c;在进行网络准入建设时&#xff0c;如何平衡好用户体验与顺利达成项目预期之间的矛盾&#xff0c;是创新企业 IT 安全团队格外…...

5G与4G的RRC协议之异同

什么是无线资源控制&#xff08;RRC&#xff09;&#xff1f; 我们知道&#xff0c;在移动通信中&#xff0c;无线资源管理是非常重要的一个环节&#xff0c;首先介绍一下什么是无线资源控制&#xff08;RRC&#xff09;。 手机和网络通过无线信道相互通信&#xff0c;彼此交…...

横扫“盲区”、“看透”缺陷,维视智造推出短波红外相机

在可见光领域&#xff0c;工业相机的视觉应用已经十分成熟&#xff0c;但在日常的客户咨询中&#xff0c;我们也经常接到一些“超纲需求”——客户想要检测“白底上的白色缺陷”、“不透明包装内的透明物体有无”等&#xff0c;均属于可见光无法实现的检测&#xff0c;而市面上…...