有两个实现类。在上一节中,我们使用了standerschedulefactory。事实上,directschedulefactory更易于快速使用。
开始:
// 直接默认启动scheduler scheduler = stdschedulerfactory.getdefaultscheduler();// 或者手动注入配置properties properties = new properties();properties.setproperty("org.quartz.scheduler.instancename", "myscheduler");properties.setproperty("org.quartz.threadpool.threadcount", "4");properties.setproperty("org.quartz.jobstore.class", "org.quartz.simpl.ramjobstore");stdschedulerfactory factory = new stdschedulerfactory(properties);scheduler scheduler = factory.getscheduler();// 3. 系统传参,指定配置文件位置 : org.quartz.properties=quartz.properties//4. 直接不用传参 ,在classpath下面建立一个 quartz.properties文件就行了.
你做了什么?配置是如何加载的?其实就是这里。org . quartz . impl . std scheduler factory # getdefaultscheduler
他在里面实例化了一堆属性,我真的觉得没写。代码太简单了。他会有一个默认的实现,所以他不怕因为没有写配置而开始出错。或者,您可以只构造方法并将其传递到配置中。
public static scheduler getdefaultscheduler() throws schedulerexception { stdschedulerfactory fact = new stdschedulerfactory(); return fact.getscheduler();}
为了组织。quartz . impl . stdschedulerfactory # instantiate()方法对比,调度器的核心方法代码有几千行,不一一展示。主要目的是初始化一堆东西,打包一堆东西。
主要是以下几个。
jobstore js = null;threadpool tp = null;quartzscheduler qs = null;dbconnectionmanager dbmgr = null;
这四个都有相同的特征,
第一 properties注入全部采用的是 set方法反射注入 ,org.quartz.impl.stdschedulerfactory#setbeanprops 这个方法里, 会set注入进去.第二 全部初始化都是 initialize方法
该接口由希望为org . quartz . core . quartz scheduler提供作业和触发存储机制的类实现& # 39;的用途。
作业和触发器的存储应该以它们的名称和组的组合作为唯一性的关键。
解释很清楚:向quartzscheduler提供一个作业和触发器的存储。同时,作业和触发器的键应该是唯一的。
org.quartz.spi.jobstore显然是存储我们工作的东西。如果我们不告诉他使用哪一个,默认实现是org . quartz . simple . ramjobstore
一个基于内存的存储,简单的包装一堆集合。主要的一点是,他将包装作业,并将其称为jobwrapper。
主要支持三种存储配置:
ram (直接jvm进程的)terracotta (terracotta是一款由美国terracotta公司开发的著名开源ja集群平台。)jdbc (mysql 之类的 ….)
希望为org . quartz . core . quartz scheduler提供线程池的类实现的接口& # 39;的用途。
理想情况下,线程池的实现实例应该只供quartz使用。最重要的是,当方法blockforailablethreads()返回值为1或更大时,在稍后(或许多时候)调用方法runinthread(runnable)时,池中必须至少有一个可用线程。如果这个假设不成立,可能会导致额外的jobstore查询和更新,如果使用了集群功能,可能会导致更大的负载不平衡。
这是整个石英的核心资源,所有的资源都在这里。
整个框架的核心….
这是quartz的核心,它是scheduler接口的间接实现,包含调度作业、注册joblistener实例等方法。
是quartz的核心,包括调用job和注册listener的方法。
构造函数,所以核心资源quartzschedulerresources也给了quartzscheduler。
public quartzscheduler(quartzschedulerresources resources, long idlewaittime, @deprecated long dbretryinterval){….}
包含所有资源(jobstore、threadpool等。)是创建quartzscheduler实例所必需的。
资源管理器,包括作业和线程池
当调度程序发现当前没有要触发的触发器时,它应该等待多长时间直到再次检查…
只是等待实施。这是一个无限循环。如果等待时间太短,就会转空很快,就是这个意思。默认值为30秒。
弃用了,就交给别人管理了。
主要实现:靠自己….
管理connectionproviders的集合,并提供对其连接的透明访问。
管理connectionproviders并提供透明的连接访问。
事实上,他是
job store-& gt;dbconnectionmanager-& gt;connectionproviders,这可以说是一种桥接模式。有一个管理器管理连接提供者,然后jobstore可以通过他获得连接。
第一点是这些都是listenermanager管理的,他的实现类是listenermanagerimpl。
让我们看看joblistener。
由希望在jobdetail执行时得到通知的类实现的接口。通常,使用调度程序的应用程序不会使用这种机制。
执行一个jobdetail。将通知您通常使用scheduler的应用程序将不使用此侦听器。
public interface joblistener { string getname(); // job调用前 void jobtobeexecuted(jobexecutioncontext context); // veto 否决的意思 , 由 org.quartz.triggerlistener#vetojobexecution 决定 void jobexecutionvetoed(jobexecutioncontext context); // job调用后 void jobwasexecuted(jobexecutioncontext context, jobexecutionexception jobexception);}public interface triggerlistener { string getname(); // 触发trigger void triggerfired(trigger trigger, jobexecutioncontext context); // 禁止执行jobexecution boolean vetojobexecution(trigger trigger, jobexecutioncontext context); // triggermisfired void triggermisfired(trigger trigger); void triggercomplete(trigger trigger, jobexecutioncontext context, completedexecutioninstruction triggerinstructioncode);}
执行过程如下。
触发器触发-& gt;
vetojobexecution?false-& gt;jobtobeexecuted-& gt;调用作业接口中的方法->:jobwascexecuted
?真-& gt;作业执行
?
很容易实现两个接口,
org.quartz.joblistener.j1.class=com.example.springquartz.myjoblistener// 比如属性设置可以这么做, 只要实现set方法就可以// org.quartz.joblistener.l1.name=myjoblistenerorg.quartz.triggerlistener.t1.class=com.example.springquartz.mytriggerlistener
这是quartz调度程序的主界面。
这是quartzscheduler的主接口,唯一对外暴露的接口,可以操作所有的资源对象。主要原因是它包含quartz调度器,所以可以操作其他对象。
我们通常是stdschedule。
主要实现:
quartzschedulerresources把所有东西都放进去。
org . quartz . core . quartz scheduler # quartz scheduler是执行任务的核心,也就是心脏。然后交给->: quartzschedulerthread轮询处理
public quartzscheduler(quartzschedulerresources resources, long idlewaittime, @deprecated long dbretryinterval) throws schedulerexception { this.resources = resources; if (resources.getjobstore() instanceof joblistener) { addinternaljoblistener((joblistener)resources.getjobstore()); } // 核心处理线程 – > 这个就是整个心脏 this.schedthread = new quartzschedulerthread(this, resources); threadexecutor schedthreadexecutor = resources.getthreadexecutor(); // 心脏启动 schedthreadexecutor.execute(this.schedthread); if (idlewaittime > 0) { this.schedthread.setidlewaittime(idlewaittime); } jobmgr = new executingjobanager(); addinternaljoblistener(jobmgr); errlogger = new errorlogger(); addinternalschedulerlistener(errlogger); signaler = new schedulersignalerimpl(this, this.schedthread); getlog().info("quartz scheduler v." getversion() " created.");}
org . quartz . core . quartz scheduler thread # run-& gt;这里描述的是quartzschedulerthread的主处理循环。
不知道是做什么的,主要用来处理作业,封装作业。
@overridepublic void run() { int acquiresfailed = 0; while (!halted.get()) { try { // 因为提前开启了 , 所以需要等待真正启动了- > 调用start, 才能继续执行. paused暂停.在 // org.quartz.core.quartzscheduler#start执行. // check if we're supposed to pause… synchronized (siglock) { while (paused && !halted.get()) { try { // wait until togglepause(false) is called… siglock.wait(1000l); } catch (interruptedexception ignore) { } // reset failure counter when paused, so that we don't // wait again after unpausing acquiresfailed = 0; } if (halted.get()) { break; } } // wait a bit, if reading from job store is consistently // failing (e.g. db is down or restarting).. if (acquiresfailed > 1) { try { long delay = computedelayforrepeatederrors(qsrsrcs.getjobstore(), acquiresfailed); thread.sleep(delay); } catch (exception ignore) { } } // 这里是获取正在等待的threadpool中的线程 . 如果有执行,你要知道`quartzschedulerresources` 把所有东西都放进去了 int ailthreadcount = qsrsrcs.getthreadpool().blockforailablethreads(); if(ailthreadcount > 0) { // will always be true, due to semantics of blockforailablethreads… // 获取当前时刻的triggers list
是始作俑者。我们知道我们必须执行一个线程。开始开始,所以这并不奇怪。上面的线程肯定是守护线程,都是,因为我们启动后不阻塞,只是gg和jvm退出。
org . quartz . core . quartz scheduler # start-& gt;给你。核心是schedthread.togglepause(false),
public void start() throws schedulerexception { if (shuttingdown|| closed) { throw new schedulerexception( "the scheduler cannot be restarted after shutdown() has been called."); } // qtz-212 : calling new schedulerstarting() method on the listeners // right after entering start() notifyschedulerlistenersstarting(); if (initialstart == null) { initialstart = new date(); this.resources.getjobstore().schedulerstarted(); startplugins(); } else { resources.getjobstore().schedulerresumed(); } // 这里设置的目的就是将它继续执行 -> `org.quartz.core.quartzschedulerthread#run`252取消暂停. schedthread.togglepause(false); getlog().info( "scheduler " resources.getuniqueidentifier() " started."); notifyschedulerlistenersstarted();}
调用qssrcs。getthreadpool()。runinthread (shell)->:调用org。quartz . simple . simple thread pool # runinthread->:那么在这个下面
public boolean runinthread(runnable runnable) { if (runnable == null) { return false; } synchronized (nextrunnablelock) { handoffpending = true; // wait until a worker thread is ailable , 这里就是等 , 等有可用的线程,这里我不理解为啥不使用队列… 其实可以使用队列的. while ((ailworkers.size() < 1) && !isshutdown) { try { nextrunnablelock.wait(500); } catch (interruptedexception ignore) { } } if (!isshutdown) { // 等到了, 拿着第一个可用线程执行 workerthread wt = (workerthread)ailworkers.removefirst(); busyworkers.add(wt); wt.run(runnable); } else { // if the thread pool is going down, execute the runnable // within a new additional worker thread (no thread from the pool). workerthread wt = new workerthread(this, threadgroup, "workerthread-lastjob", prio, iakethreadsdaemons(), runnable); busyworkers.add(wt); workers.add(wt); wt.start(); } // 释放锁 nextrunnablelock.notifyall(); handoffpending = false; } // 返回ok , 这里其实是异步的 , 因为处理流程交给了子线程, 他只是返回了他已经处理了, 但是有一个问题就是线程处理时间过长, 就会影响周期性.(所以建议设置多点,但是也不好,线程一直处于不断运行阶段) return true;}
调用wt . run(runnable);-& gt;调用组织。quartz . simple . simple thread pool . worker thread # run(ja . lang . runnable)来执行run方法。
public void run(runnable newrunnable) { synchronized(lock) { if(runnable != null) { throw new illegalstateexception("already running a runnable!"); } runnable = newrunnable; lock.notifyall(); }}
然后执行等待线程,等待–>:等待下面的执行。..
org . quartz . simple . simple thread pool . worker thread # run()每个工作线程在初始化的时候都一直在这里等待。等等等等等等等等。
@overridepublic void run() { boolean ran = false; // 转 …. while (run.get()) { try { // 同步等待. 500ms , 直到有 runnable … 很可怜, 其实基本大多都是这么实现的 eventloop synchronized(lock) { while (runnable == null && run.get()) { lock.wait(500); } if (runnable != null) { ran = true; // 启动任务, 这里直接将runnable对象启动, 而不是new thread(runnable).start,而是直接调用的方式. 让这个线程去处理. runnable.run(); } } } catch (interruptedexception unblock) { // do nothing (loop will terminate if shutdown() was called try { getlog().error("worker thread was interrupt()'ed.", unblock); } catch(exception e) { // ignore to help with a tomcat glitch } } catch (throwable exceptioninrunnable) { try { getlog().error("error while executing the runnable: ", exceptioninrunnable); } catch(exception e) { // ignore to help with a tomcat glitch } } finally { synchronized(lock) { runnable = null; } // repair the thread in case the runnable mucked it up… if(getpriority() != tp.getthreadpriority()) { setpriority(tp.getthreadpriority()); } if (runonce) { run.set(false); clearfrombusyworkerslist(this); } else if(ran) { ran = false; makeailable(this); } } } //if (log.isdebugenabled()) try { getlog().debug("workerthread is shut down."); } catch(exception e) { // ignore to help with a tomcat glitch }}
public class demo { public static final object object = new object(); public static void main(string[] args) throws interruptedexception { long start = system.currenttimemillis(); while (true) { synchronized (object) { system.out.println("time : " (system.currenttimemillis() – start) "ms."); object.wait(1000l); } } }}
输出
time : 0ms.time : 1000ms.time : 2001ms.time : 3002ms.time : 4002ms.time : 5003ms.
石英框架分析一波,主要类似于nio的思路。主线程不断地监视和轮询工作线程,同时也监视触发器,看是否可以触发。是的,找一个空闲的工作线程来处理,所以是nio的主意。
但是,有几个问题。如果初始化线程(工作线程)太多,这些线程在初始化阶段就会被启动,所以会消耗cpu资源。
如果初始化线程(工作线程)太少,很容易阻塞,所以………………
他的设计框架还是很不错的。可以说是一个设计模式,整体设计完全解耦。挺好看的。其实学习框架是为了完善自己的设计思路,不断学习和发现新的世界。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文链接:https://www.andon8.com/66470.html