quartz框架(六)-ThreadPool
ThreadPool
本篇博文,博主将介绍Quartz框架中ThreadPool线程池相关的内容。线程池顾名思义,就是一个可以帮助我们来进行线程资源管理的对象。在web开发中,常见的就有数据库连接池,http连接池,redis连接池等。在看这篇文章之前,读者需要先具备一定的多线程和锁的知识,如使用wait和notify方法,实现生产者和消费者功能。
为什么要用线程池?
- 线程池可以复用线程,减少线程的创建和销毁次数。
- 可以提高程序的响应速度。
- 可以对线程资源进行统一管理,比如监控。
- ...
接口定义
quartz框架中的ThreadPool接口定义如下,博主在相应的接口方法上进行了注释。
public interface ThreadPool {
//将runnable接口放入到Thread中执行
boolean runInThread(Runnable runnable);
//阻塞获取可用线程数
int blockForAvailableThreads();
//线程初始化方法
void initialize() throws SchedulerConfigException;
//关闭线程
void shutdown(boolean waitForJobsToComplete);
//获取线程池大小
int getPoolSize();
//设置实例id
void setInstanceId(String schedInstId);
//设置实例名称
void setInstanceName(String schedName);
}
WorkThread
在介绍SimpleThreadPool之前,博主先讲解一下WorkThread。WorkThread继承了Thread类,因此它是一个可以被运行的线程。它会阻塞式的接收线程池分配的任务,然后执行对应的任务。
工作者线程属性
- lock,任务执行锁。
- tp,工作者线程所在的线程池。
- runnable,可以运行的任务。
- runOnce,是否只执行一次。通过构造函数传runnable实例,此时runOnce为true。
- run,是否需要循环执行。
Runnable的run方法
工作者线程启动之后,在一个while循环里面执行业务逻辑。while循环的退出条件是线程是否关闭(run == false)。先去获取任务锁(lock对象),如果没有关闭且当前runnale方法为空,说明此时没有需要执行的任务。线程会在这里等待500毫秒(wait 500)。当有任务投递给当前线程时,才会唤醒工作者线程,继续执行当前方法。
如果任务不为空的话,执行runnable接口。执行完之后获取lock锁,防止并发冲突。获取到锁之后,设置runnable接口为null。如果只是只执行一次的任务,通过持有的threadPool引用,去获取下一次任务允许的锁,获取到下一次任务允许的锁之后,那么就将自己从busyWorks中移除。否则就从busyWorkers中移除,然后添加到avaliableWorkers。
自定义的run方法
内部的run(Runnable newRunnable)方法:先去获取内部对象lock的锁,获取成功后先判断内部的runnable是否为空。如果不为空的话说明该线程还是处于繁忙状态,抛出异常。如果为空的话,则设置为传递进来的newRunnable,并且唤醒所有lock等待队列中的对象(提前让这些对象结束等待,提高工作线程的响应速度)。
shutdown方法
设置内部成员变量run为false,也就是任务执行完之后不再循环等待下一个可以运行的任务,结束线程的run方法后,线程会进入terminate状态。
SimpleThreadPool
在quartz默认的配置文件中,使用的是SimpleThreadPool这个线程池,并且指定了线程池的个数为10。从源码中,我们也可以看到SimpleThreadPool是一个线程大小固定的线程池。代码如下所示:
public SimpleThreadPool(int threadCount, int threadPriority) {
setThreadCount(threadCount);
setThreadPriority(threadPriority);
}
线程池属性
- count,线程个数
- isShutdown,是否处于关闭状态
- handoffPending,是否处于切换状态
- makeThreadsDaemons,创建的线程是否为后台线程
- threadGroup,线程组
- nextRunnableLock,下一个可以运行的任务锁
- workers,总共线程集合
- availWorkers,空闲线程集合
- busyWorkers,繁忙线程集合
- threadNamePrefix,线程名称前缀
- schedulerInstanceName,调度器实例名称
initialize方法
在QuartzScheduler对象进行初始化的时候,就会创建对应的线程池,并且调用对应的initialize方法。initialize方法主要就是预先创建对应个数的工作者线程,并且将它们添加到workers和availWorkers集合中,并且循环调用每个workThread的start方法。
blockForAvailableThreads方法
先获取到下一次运行的任务锁,防止这时候的空闲线程集合availWorkers发生变化。如果此时的availWorkers小于1,或者此时有任务进行等待分配,并且此时线程池没有关闭,那么就进行等待(wait 500)。
如果此时获取到的空闲线程数大于等于1,则说明现在可以把对应个数的任务交给线程池进行分配执行。
runInThread方法
先获取到可以允许下一个任务的锁(nextRunnableLock),设置handoffPending为true,handoffPending表示当前有任务在等待线程池分配任务。接着阻塞判断是否存在空闲线程可以获取(繁忙线程执行完后会将自己添加到空闲线程集合中)或者 线程池是否需要被关闭。
如果没有关闭线程池的情况下,直接从空闲线程中拿到第一个线程,并从空闲集合中移除。然后将这个空闲线程添加到繁忙线程集合中,接着执行workThread的投递方法(run方法)。
如果将要关闭线程池的情况下,直接new出一个线程去执行这个任务,不再等待有空闲线程去执行,加快线程池的shutdown时间。并将此线程添加到繁忙线程集合中,添加到工作者集合中。
最后通知等待下一次允许任务锁的线程,设置handoffPending为false。
shutdown
关闭线程池时,一个需要停止上游线程(quartzThread)给他(thradPool)分配任务,另一个需要关闭掉工作池中现有的任务。如果这时候刚好有任务需要进行调度,则需要看配置waitForJobsToComplete。
关闭线程池的方法有一个waitForJobsToComplete的方法,waitForJobsToComplete表示线程池关闭是否需要等到运行中的任务执行完毕。接着设置线程池为关闭状态(shutdown),并循环调用workers集合中thread的shutdown方法(不让工作者线程再循环执行),然后移除availWorkers中的线程。
如果waitForJobsToComplete为true,那么判断busyWorkers的元素个数是否大于0(繁忙集合中的线程结束任务后,会将自己从繁忙集合中移除),如果busyWorkers的元素个数大于0的,调用nextRunnableLock的阻塞方法,让其它方法有时间处理(比如如果此时有任务需要进行分配,可以让线程池把任务分配好)。最后循环调用每个workers中thread的join方法,等待thread死亡。
博主微信公众号
quartz框架(六)-ThreadPool的更多相关文章
- Quartz框架调用——运行报错:ThreadPool class not specified
Quartz框架调用——运行报错:ThreadPool class not specified 问题是在于Quartz框架在加载的时候找不到quartz.properties配置文件: 解决方案一: ...
- Quartz框架多个trigger任务执行出现漏执行的问题分析--转
原文地址:http://blog.csdn.net/dailywater/article/details/51470779 一.问题描述 使用Quartz配置定时任务,配置了超过10个定时任务,这些定 ...
- Quartz框架调用Demo
Quartz框架调用Demo 任务调度在JAVA应用程序中运用的十分普遍,掌握QUARTZ是必备的技能; 官网:http://www.quartz-scheduler.org/ 下载最新1.80资源包 ...
- Quartz 框架 教程(中文版)2.2.x
Quartz 框架 教程(中文版)2.2.x 之第一课 开始使用Quartz框架 Quartz 框架 教程(中文版)2.2.x 之第二课 Quartz API,Jobs和Triggers简介 Quar ...
- quartz框架(十)-QuartzShedulerThread
QuartzSchedulerThread 本篇博文,博主将介绍QuartzSchedulerThread的相关内容.话不多说,直接进入正题. 什么是QuartzSchedulerThread? 从源 ...
- Quartz框架(第一版)
任务调度 在企业级应用中,经常会制定一些"计划任务",即在某个时间点做某件事情 核心是以时间为关注点,即在一个特定的时间点,系统执行指定的一个操作 任务调度涉及多线程并发.线程池维 ...
- Quartz框架
Quartz框架 Quartz 是个开源的作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制.Quartz 允许开发人员根据时间间隔(或天)来调度作业.它实现了作业和触发器的多 ...
- 【淘淘】Spring整合Quartz框架
我在外面工作实习的时候,我们做的项目是一个日报子系统,也就是定时定点为公司生成一些报表数据还有一些数据反馈.这时候我们会经常用到定时任务,比如每天凌晨生成前天报表,每一小时生成汇总数据等等.当时,我做 ...
- java任务调度quartz框架的小例子
quartz是一个开源的作业调度框架,当然,java可以使用Timer来实现简单任务调度的功能,但Timer是单线程的设计方案,使得一个任务延迟会影响到其他的任务.java也可以使用Scheduled ...
随机推荐
- halcon视觉入门扫盲篇
halcon视觉入门扫盲篇 前言 在公司让我研究视觉的时候,我是两眼一抹黑的.之前完全没有接触过视觉.综合权衡后选择了Halcon,使用的是HDevelop 13 (64-bit). ...
- 【XR-2】伤痕
不难发现,直接漫无目的地构造不是一个好的选择,因为我们并不知道选择四座城市方案的上界是什么,因此下面可以来先分析一下这个方案的上界. 首先可以考虑这使得这四个点的导出子图是强连通的方案数,但是经过尝试 ...
- bom-offset
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- opencv结构IplImage
转载请注明来源:https://www.cnblogs.com/hookjc/ typedef struct _IplImage{int nSize; /* Ip ...
- MySQL里的那些日志们
该系列博文会告诉你如何从入门到进阶,从sql基本的使用方法,从MySQL执行引擎再到索引.事务等知识,一步步地学习MySQL相关技术的实现原理,更好地了解如何基于这些知识来优化sql,减少SQL执行时 ...
- C# 实例解释面向对象编程中的开闭原则
在面向对象编程中,SOLID 是五个设计原则的首字母缩写,旨在使软件设计更易于理解.灵活和可维护.这些原则是由美国软件工程师和讲师罗伯特·C·马丁(Robert Cecil Martin)提出的许多原 ...
- world.construct(me);
目录 0 引言 0.1 所谓构造题 0.2 重点是动机 (motivation) 1 实践出真知 1.1 「CSP-S 2021」「洛谷 P7915」回文 1.1.1 题目大意 1.1.2 解题过程 ...
- Linux性能优化之内存性能调优
一.根据性能指标找工具 二.根据工具查性能 三.内存优化策略 常见的优化思路有这么几种: 1)最好禁止 Swap.如果必须开启 Swap,降低 swappiness 的值,减少内存回收时 Swap 的 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(二十)——Saga框架实现思路分享
今天这篇博文的主要目的是分享一下我设计Saga的实现思路来抛砖引玉,其实Saga本身非常的类似于一个简单的工作流体系,相比工作流不一样的部分在于它没有工作流的复杂逻辑处理机制(比如会签),没有条件分支 ...
- 使用java程序完成大量文件目录拷贝工作
java程序完成目录拷贝工作 背景描述:我目录有140多个,每个目录里面都有一个src目录.我现在想要所有的src目录移动到同一个目录中. package com.util.cp; import ja ...