【JavaEE】线程池和定时器
🔥个人主页: 中草药
🔥专栏:【Java】登神长阶 史诗般的Java成神之路
✏️一.线程池
在Java中,线程池(Thread Pool)是一种用于管理并发线程的机制,它提供了一种创建、复用和管理一组线程的方法,这些线程可以用来执行提交的任务。线程池的使用可以显著提高程序的性能和响应能力,尤其是在处理大量并发任务时。Java的java.util.concurrent
包提供了丰富的API来创建和管理线程池,其中最核心的接口是ExecutorService
,以及其实现类ThreadPoolExecutor
。
创建
Java中线程池的创建主要通过Executors
工厂类或直接使用ThreadPoolExecutor
类来完成:
-
使用
Executors
工厂类:newSingleThreadExecutor()
:创建一个单线程的线程池,它只会创建一个线程来执行任务。newFixedThreadPool(int nThreads)
:创建一个固定大小的线程池,线程数量由nThreads
参数确定。newCachedThreadPool()
:创建一个可缓存的线程池,线程数量没有上限,当长时间没有新任务时,空闲线程会被终止。newScheduledThreadPool(int corePoolSize)
:创建一个可以安排任务的线程池,可以指定延迟执行任务或定期执行任务。
-
使用
ThreadPoolExecutor
类:
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
:这是一个构造函数,可以自定义线程池的核心参数,如核心线程数、最大线程数、线程空闲时间、工作队列等。
使用
- 提交任务:使用
execute(Runnable command)
或submit(Callable<T> task)
方法提交任务到线程池。 - 关闭线程池:使用
shutdown()
方法关闭线程池,等待所有已提交的任务完成;使用shutdownNow()
方法立即关闭线程池并尝试取消正在执行的任务。
举例
- 使用Executors.newFixedThreadPool (5) 能创建出固定包含10个线程的线程池
- 返回值类型为ExecutorService
- 通过ExecutorService.submit可以注册一个任务到线程池中
public static void main(String[] args) throws InterruptedException {ExecutorService service= Executors.newFixedThreadPool(5);for (int i = 0; i < 100; i++) {int id=i;service.submit(()->{System.out.println("执行任务"+id+";"+Thread.currentThread().getName());});}// 最好不要立即就终止, 可能使任务还没执行完呢, 线程就被终止了.Thread.sleep(2000);// 关闭线程池service.shutdown();System.out.println("程序退出");}
线程池配置参数分析*
-
核心线程数-CorePoolSize
- 参数名:
corePoolSize
- 描述:线程池中保持的线程的最少数量。即使线程池中没有任务需要执行,只要线程的数量不超过
corePoolSize
,线程池就不会销毁线程。这样可以保证线程池随时准备接收新的任务,而不需要频繁地创建和销毁线程。
- 参数名:
-
最大线程数-MaximumPoolSize
- 参数名:
maximumPoolSize
- 描述:线程池中允许的最大线程数量。当线程池中的活动线程数量达到
maximumPoolSize
后,线程池不会创建新的线程,而是将任务放入工作队列中等待执行。如果工作队列已满,线程池会采取拒绝策略处理新任务。
- 参数名:
-
空闲线程存活时间-KeepAliveTime
- 参数名:
keepAliveTime
- 描述:当线程池中的线程数量超过
corePoolSize
时,超出的线程会在没有任务可执行时等待的时间长度。如果在keepAliveTime
时间内没有新任务到来,超出的线程将被终止。这有助于控制线程池的规模,避免在任务量减少时线程资源的浪费。
- 参数名:
-
时间单位-Unit
- 参数名:
unit
- 描述:配合
keepAliveTime
使用,指定空闲线程存活时间的单位,如毫秒、秒、分钟等。
- 参数名:
-
工作队列-WorkQueue
- 参数名:
workQueue
- 描述:用于存放等待执行的任务的阻塞队列。当线程池中的线程数量达到
corePoolSize
且所有线程都在执行任务时,后续到达的任务会被放置在工作队列中等待执行。常见的队列类型有ArrayBlockingQueue
(有界队列)、LinkedBlockingQueue
(有界或无界队列)、SynchronousQueue
(不存储元素的队列)等。
- 参数名:
-
拒绝策略-RejectedExecutionHandler
- 参数名:
handler
- 描述:当线程池无法接受新任务时(即线程数量达到
maximumPoolSize
且工作队列已满)所采取的策略。
- 参数名:
常见的拒绝策略
AbortPolicy
:抛出RejectedExecutionException
异常。CallerRunsPolicy
:由调用者线程执行该任务,即直接在调用execute
方法的线程中执行任务。DiscardPolicy
:静默丢弃无法处理的任务。DiscardOldestPolicy
:丢弃队列中最老的任务,并尝试再次提交新任务。
模拟实现
- 核心操作为submit,将任务加入线程池
- 使用Runnable描述一个任务
- 使用一个BlockingQueue组织所有任务
- 不停从BlockingQueue中取任务并执行
class MyThreadPool{private BlockingQueue<Runnable> queue=new ArrayBlockingQueue<>( 1000);public MyThreadPool(int n){//此处的n表示可以创建几个线程for (int i = 0; i < n; i++) {Thread t=new Thread(()->{while(true){try {Runnable runnable = queue.take();runnable.run();} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();}}/*** 添加任务* @param runnable*/public void submit(Runnable runnable){try{queue.put(runnable);}catch (InterruptedException e){throw new RuntimeException(e);}}
}
测试代码
public static void main(String[] args) {MyThreadPool pool=new MyThreadPool(5);for (int i = 0; i < 100; i++) {int id=i;pool.submit(()->{System.out.println("执行任务"+id+";"+Thread.currentThread().getName());});}}
测试结果
✒️二.定时器
在Java中,定时器(Timer)是一个重要的工具,用于执行定时任务,无论是单次的还是周期性的,类似于一个闹钟,到达一个设定的时间之后就会执行某个指定好的代码Java提供了多种方式来实现定时任务。
基本使用
其中最常用的是java.util.Timer
类和java.util.concurrent.ScheduledExecutorService
接口。下面将详细介绍这两种实现方式。
java.util.Timer
类
java.util.Timer
是一个简单的定时器类,它使用一个单独的守护线程来调度和执行任务。它通常与java.util.TimerTask
一起使用,后者是java.util.Timer
类的任务执行单元。
public static void main(String[] args) {Timer timer=new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello 3");}},3000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello 2");}},2000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello 1");}},1000);}
注意事项
- 在使用定时器时,一定要处理好任务执行中可能出现的异常,否则守护线程可能因为异常而终止,导致定时器失效。
- 确保在应用程序结束前正确地关闭定时器,避免线程泄露和资源浪费。
- 考虑到线程安全和并发控制,
ScheduledExecutorService
在大多数情况下是更好的选择,尤其是当任务需要并发执行时。
模拟实现
package demo;import java.util.PriorityQueue;
import java.util.Timer;
import java.util.TimerTask;/*** 模拟实现定时器*/
class MyTimerTask implements Comparable<MyTimerTask> {private Runnable runnable;private long time;//此处的time是毫秒时间戳,表示这个任务具体啥时候执行public MyTimerTask (Runnable runnable,long delay){this.runnable=runnable;this.time=System.currentTimeMillis()+delay;}public void run(){runnable.run();}public long getTime(){return time;}@Overridepublic int compareTo(MyTimerTask o) {// 此处这里的 - 的顺序, 就决定了这里是大堆还是小堆.// 此处需要小堆.return (int)(this.time-o.time);}
}class MyTimer{private PriorityQueue<MyTimerTask> queue=new PriorityQueue<>();//如果用List不是最好的选择,在后续执行列表中任务时,需要依次遍历每个元素private Object locker=new Object();//创建线程,负责执行上述队列中的内容public MyTimer(){Thread t=new Thread(()->{try{while(true){synchronized(locker){while(queue.isEmpty()){locker.wait();}MyTimerTask current=queue.peek();if (System.currentTimeMillis()>=current.getTime()){//执行该任务current.run();//将执行过的任务从队列中删除queue.poll();}else{//暂且不执行locker.wait(current.getTime()-System.currentTimeMillis());}}}}catch (InterruptedException e){throw new RuntimeException(e);}});t.start();}public void schedule(Runnable runnable,long delay){synchronized(locker){MyTimerTask current=new MyTimerTask(runnable,delay);queue.offer(current);locker.notify();}}}
测试代码
public static void main(String[] args) {MyTimer timer=new MyTimer();timer.schedule(()->{System.out.println("倒计时 2");},2000);timer.schedule(()->{System.out.println("倒计时 1");},3000);timer.schedule(()->{System.out.println("倒计时 3");},1000);//证明优先级队列的作用}
结果
🖋️三.总结与反思
在深入研究Java并发编程的过程中,线程池和定时器是两个不可或缺的概念。它们不仅体现了Java在处理并发和定时任务上的强大功能,也反映了现代软件工程中资源管理和效率优化的重要性。以下是我在学习这两个主题后的总结与反思。
线程池:高效资源管理的艺术
线程池,顾名思义,是一个预先创建好的线程集合,用于执行提交的任务。它通过复用现有线程,避免了线程创建和销毁的开销,从而提高了系统的响应速度和资源利用率。线程池的配置参数,如核心线程数、最大线程数、工作队列类型等,需要根据具体的应用场景和系统资源进行细致调整。合理配置的线程池能够显著提升并发任务的处理能力,减少资源浪费,是高性能服务器应用的基石。
在实际应用中,我深刻体会到线程池的配置需要平衡并发度与系统负载。过多的线程可能导致系统资源紧张,而过少的线程则可能无法充分利用系统资源。此外,线程池的管理,如任务的排队策略、异常处理、线程的生命周期管理等,也是实现高效、健壮系统的关键。
定时器:精准时间控制的利器
定时器则是在Java中执行定时任务的重要工具。无论是简单的java.util.Timer
,还是更强大的java.util.concurrent.ScheduledExecutorService
,它们都提供了执行周期性或一次性定时任务的能力。定时器的使用极大地丰富了Java在事件驱动、任务调度等方面的功能,是实现自动化运维、数据定时处理等场景的基础。
在使用定时器时,我注意到几个关键点:首先,选择合适的定时器类型至关重要。Timer
简单易用,但ScheduledExecutorService
提供了更高级的调度策略和更好的并发支持。其次,定时任务的异常处理不容忽视,否则可能导致任务执行失败而不被察觉。最后,正确关闭定时器,避免线程泄露,是编写健壮程序的必要步骤。
反思
通过学习和实践线程池与定时器,我深刻理解到并发编程的复杂性和魅力。在设计系统时,不仅要考虑功能的实现,还要兼顾性能、资源管理和错误处理。线程池和定时器的合理应用,能够显著提升软件的响应速度和稳定性,但同时也对程序员提出了更高的要求。
面向未来,随着云计算和分布式系统的普及,线程池和定时器的概念将更加重要。如何在分布式环境中高效、安全地管理线程和执行定时任务,将成为新一代软件工程师面临的新挑战。掌握线程池和定时器的原理及最佳实践,无疑将为迎接这些挑战打下坚实的基础。
总之,Java中的线程池和定时器不仅是编程技巧的体现,更是现代软件工程思想的反映。通过深入学习和不断实践,我期待能够将这些知识应用于更复杂的系统设计和开发中,创造出既高效又可靠的软件产品。
🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀
以上,就是本期的全部内容啦,若有错误疏忽希望各位大佬及时指出💐
制作不易,希望能对各位提供微小的帮助,可否留下你免费的赞呢🌸
相关文章:
【JavaEE】线程池和定时器
🔥个人主页: 中草药 🔥专栏:【Java】登神长阶 史诗般的Java成神之路 ✏️一.线程池 在Java中,线程池(Thread Pool)是一种用于管理并发线程的机制,它提供了一种创建、复用和管理一组…...
《Unity3D网络游戏实战》通用服务器框架
服务端程序的两大核心是处理客户端的消息和存储玩家数据 模块划分 游戏流程 连接阶段:客户端调用Connect连接服务端即为连接阶段。连接后双端即可通信,但服务端还不知道玩家控制的是哪个角色。于是客户端需要发送一条登录协议,协议中包含用户…...
LeetCode404 左叶子之和
前言 题目: 404. 左叶子之和 文档: 代码随想录——左叶子之和 编程语言: C 解题状态: 成功解答! 思路 注意左叶子节点的定义:节点A的左孩子不为空,且左孩子的左右孩子都为空(说明是…...
nodejs操作redis的工具类
const Redis require("ioredis");async function generateStreamID() {// 生成时间戳(毫秒级)const timestamp Date.now();// 生成唯一的序列号const sequenceNumber Math.random() * 1000; // 根据需要生成唯一的序列号// 构建 Stream ID&…...
关于wsl2与win11互联互通的问题
首先搞清楚使用场景。我是在win11上写go做后端api,在WSL2 的Linux上写前端页面。 我发现在windows 里写go语言没啥问题,我的后端api部署在win11上。但是在win11上写前端经常会遇到莫名其妙的故障,一会npm包下不来一会说包之间的依赖结构出问题…...
C++ 类型转换
目录 0.前言 1.C语言类型转换 1.1隐式类型转换 1.2显式类型转换 2.C强制类型转换 2.1 static_cast 2.2 reinterpret_cast 2.3 const_cast 2.4 dynamic_cast 3.为什么C需要4种强制类型转换 3.1类型转换的多样性需求 3.2提高类型转换的安全性 3.3提供更明确的语义 3.4支持高级编程…...
2024挖漏洞给报酬的网站汇总,兼职副业3天收益2k
文章目录 一、众测平台(国内)二、前沿漏洞研究奖励计划三、行业SRC四、企业应急响应中心-SRC-汇总 1、互联网企业2、生活服务、住宿、购物相关企业3、物流、出行、旅游4、金融相关企业5、视频游戏直播社交娱乐6、教育、问答、知识付费7、泛科技通讯物联网云服务8、安全企业9、其…...
0到1学习Google广告(2):掌握展示位置及排名规则丨出海笔记
大家好, 我是专注谷歌广告和谷歌SEO的谷哥哥哥,感谢出海笔记Alan邀请。今天我们来聊聊广告界的大拿——谷歌广告。在这个数字营销的黄金时代,无论是B2B、B2C还是品牌类客户,谷歌广告都是一个不容忽视的战场。那么,如何在这个战场上…...
MySQL数据库读超时/SELECT查询超时 杂记
本文环境 阿里云RDS MySQL 8.0.34 当客户端向MySQL数据库发送一条SQL之后,由于SQL很慢很慢,它会在什么时候结束呢? 查看 max_execution_time 变量值 mysql> show variables like max_execution_time; --------------------------- | Variable_name | Value | ------…...
docker数据卷:
docker数据卷: 容器和宿主机之间数据共享 容器和宿主机之间数据共享——————挂载卷————容器内的目录和宿主机的目录进行挂载,实现数据文件共享 容器的生命周期有限,一旦重启所有对容器内部文件数据的修改以及保存的数据都会被初始…...
【linux】linux中如何通过systemctl来创建和管理服务
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…...
WPF-实现多语言的静态(需重启)与动态切换(不用重启)
目录 一、多语言切换(需重启) 1、配置文件添加Key 2、新增附加属性当前选择语言 3、创建资源文件 4、初始化多语言集合 5、切换多语言并更新配置文件 6、应用程序启动根据配置切换多语言 7、使用 二、多语言切换(无需重启)…...
UE5学习笔记12-为角色添加蹲下的动作
一、一点说明 1.蹲下使用了ACharacter类中Crouch();函数,函数功能是先检查是否存在运动组件,将bool类型的变量变为true,该变量代表是想要蹲下。 2.通过源码可知存在是否蹲下的bool变量bIsCrouched如图,如果对:1有疑问请搜索C位域 …...
【笔记】Android 多用户模式和用户类型
简介 用户界面:System 》Multiple Users 》 开关多用户模式。 一般是不同用户模式下,有修改Settings应用配置的权限差异,因此需要通过用户类型对功能进行判断限制。 代码 通过UserManager可以获取当前用户的信息。 frameworks/base/core/…...
SQL基础——MySQL的索引
简介:个人学习分享,如有错误,欢迎批评指正。 一、概述 介绍 索引是通过某种算法,构建出一个数据模型,用于快速找出在某个列中有一特定值的行,不使用索引,MySQL必须从第一条记录开始读完整个表&…...
【开发语言】面向对象和面向过程开发思路的区别
引入: 我总结了 面向过程的开发语言思路:1.我要干啥?2.怎么才能实现 面向对象的开发语言思路:1.我要研究谁?2.他能干啥 详解: 面向过程的开发语言思路 我要干啥? 在面向过程的开发中&a…...
谷歌账号登录的时候提示被停用,原因是什么,账号还有救吗?该如何处理?
今日早上,有个久违的朋友找到我说,要恢复账号。 他的情况是这样的:7月21日的时候,他发现自己的谷歌账号登录的时候提示活动异常先,需要输入手机号码验证才能恢复账号。但是输入了自己和亲友们的多个手机号码都无法验证…...
数据库复习笔记
写在最前, 写文章的初衷只是为了复习与记录自己的成长,笔者目前水平还有待提高,文章中难免会出现许多问题与错误,文章内容仅供参考,有不足的地方还请大家多多包涵并指正,谢谢~ 第八章 T-SQL程序结构 8.…...
学习STM32(6)-- STM32单片机ADCDAC的应用
1 引 言 深入了解并掌握STM32F103单片机在模拟数字转换(ADC)和数字模拟转换(DAC)应用方面的功能和操作。学习如何配置STM32F103的ADC模块,实现模拟信号到数字信号的精确转换;同时,探索DAC模块…...
学习记录第二十五天
wait函数 wait函数是一个系统调用,用于等待一个子进程结束并回收其资源。当父进程调用wait函数时,它会暂停执行,直到至少有一个子进程结束。wait函数的原型如下: #include <sys/types.h> #include <sys/wait.h>pid_…...
C语言:字符串函数strcmp
该函数用于比较两个字符串是否一样。 使用方法如下: #include<stdio.h> #include<string.h>int main() {//strcmp函数返回值有三种情况,小于零时返回-1,等于零,大于零时返回1printf("%d\n", strcmp("…...
【数据分析---偏企业】 Excel操作
各位大佬好 ,这里是阿川的博客,祝您变得更强 个人主页:在线OJ的阿川 大佬的支持和鼓励,将是我成长路上最大的动力 阿川水平有限,如有错误,欢迎大佬指正 Excel操作前 必看 Python 初阶 Python—语言基础与…...
Ajax-01.原生方式
<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Ajax-原生方式</title> </head> <!-…...
OpenAI GPT-2 model use with TensorFlow JS
题意:使用 TensorFlow JS 应用 OpenAI GPT-2 模型 问题背景: Is that possible to generate texts from OpenAI GPT-2 using TensorFlowJS? 是否可以使用 TensorFlowJS 生成 OpenAI GPT-2 的文本? If not what is the limitation, like mo…...
JVM-运行数据区(堆、栈、元空间)
文章声明:文章图片均来自互联网,因为本人画的图不够生动。 运行数据区是JVM最重要的一个区域。 运行数据区由栈、堆、元空间构成。 栈:程序计数器、JVM虚拟机栈,本地方法栈 本地方法栈:加载native修饰的方法&#…...
超详细!!! LVS(Linux virual server)负载均衡知识及其NAT模式、DR模式、火墙标记实验
目录 前言系统性能扩展方式集群Cluster分布式集群与分布式 四层转发与七层转发的区别 LVS(Linux virual server)一、LVS介绍LVS相关概念 二、LVS集群结构体系1. 负载均衡层(Load Balancer)2. 服务器群组层(Server Pool…...
信息学奥赛一本通1259:【例9.3】求最长不下降序列
题目: 1259:【例9.3】求最长不下降序列 时间限制: 1000 ms 内存限制: 65536 KB 提交数:51218 通过数: 20928 Special Judge 【题目描述】 设有由n(1≤n≤200)n(1≤n≤200)个不相同的整数组成的数列,记为:b(1)、b(2)、……、…...
星露谷模组开发教程#3 事件
首发于Enaium的个人博客 SMAPI提供了一些事件,比如游戏的内容、显示、输入等事件。这些事件可以让我们在游戏中添加自己的逻辑。这一节我们就来看看如何使用这些事件。 注册一个事件 在SMAPI中,我们可以通过IModHelper的Events属性来注册事件。比如我们…...
C语言程序设计(初识C语言后部分)
愿天下无Bug,秀发常驻。 3)函数的参数 1.实际参数(实参): 真实传给函数的参数,叫实参。 实参可以是:常量、变量、表达式、函数等。 无论实参是何类型的量,在进行函数调用时&#…...
驱动基础开发
1、字符设备传统开发模板 字符设备驱动框架,首先我们需要去用module_init这个宏去修饰整个驱动的入口函数,用module_exit去修饰整个驱动的出口函数,然后还需要用MODULE_LICENSE用于声明模块的许可证类型。 在入口函数里面我们需要注册字符设…...
ppt素材网站建设流程图/缅甸新闻最新消息
百度智能云 云生态狂欢季 热门云产品1折起>>> 据外媒报道,一名负责维护 Linux 内核的 Amazon 开发者可能发布了内核最大的功能补丁集 —— 实现完全公平调度器(CFS)的协同调度支持。亚马逊德国公司的 Jan H. Schoenherr 在一系列补丁集中(包含…...
日本做美食视频网站/广告位招商怎么找客户
BabyBluetooth 是一个最简单易用的蓝牙库,基于CoreBluetooth的封装,并兼容ios和mac osx。 特色: 基于原生CoreBluetooth框架封装的轻量级的开源库,可以帮你更简单地使用CoreBluetooth API。CoreBluetooth所有方法都是通过委托完成…...
做网站开发的电话销售话术/海城seo网站排名优化推广
测试用例是进行测试的最小单元粒度。在编写测试用例之前需要很多准备工作去分析需求,提取测试点,然后根据提取的测试点选择相应分析方法,来设计测试用例。但测试用例如果要自己在excl手动填写,制作用例模板时,需要注意…...
win7搭建wordpress/百度信息流平台
设计模式是重复发生的问题的解决方案。 一个模式一般包含如下几部分: 名称:隐含了模式要解决的问题、方案、效果等 问题:描述了模式的应用场景。准确的理解模式对应的问题,是理解模式的关键,也是实践中应用模式的关键 …...
wordpress nginx配置文件/整合营销的案例
3.Docker 数据管理 如果将正在运行中的容器修改生成了新的数据,或者修改了现有的一个已经存在的文件内容,那么新产生的数据将会被复制到读写层,进行持久化保存,这个读写层也就是容器的工作目录,此即“写时复制(COW) copy on write”机制。 如下图是将对根的数据写入到了…...
手机网页制作与网站建设/河北seo推广公司
由于TC2和TC3都有可能用到,个人推荐都安装,但是注意必须是先安装的TwinCAT2,然后安装TwinCAT3,如果反了可能两个都没法用(打开TcSwitchRuntime提示Both TwinCAT are activated,这样你一个也无法禁用&#x…...