应用场景:前端上传语音文件,后端收到该语音文件后(可以预估出该语音文件总时长),然后将其上传ftp服务器,后端的task模块通过对ftp服务器上的文件夹扫描,获取该语音文件,然后将其上传语音识别系统进行识别,识别出来结果后上传ftp服务器,task中控通过消息队列(后台订阅该队列)通知后台去ftp获取该语音文件。然后读取该文件,将其推动到其前端。前端将其结果展示出来。
那么定时任务用到什么地方呢?
在前端上传文件成功(其实是后台获取到了)后,后台要返回给前端几个参数,其中一个参数是该文件的倒计时剩余时长,如果在前端倒计时结束时,中控仍然没有通知后台文件识别成功,那么前端就判断该文件识别失败。
那倒计时到底用到那里了呢?
当task中控通知后台语音文件已经被是被识别成功后,该文件的状态(上传成功时,后台令该文件状态fileStatus=0,并写在redis中),就要变为fileStatus=1,并通过webSocket推送到前端。 但后端的倒计时(预估的文件时长)结束时去redis查看,发现redis中该文件(callId标识)状态仍然没有改变,那么就令redis中该文件的状态fileStatus=-1(识别失败),并推送给前端。
所以,你看到了吗,前端和后端均维持了个倒计时,但当前端页面上的刷新后(前端的倒计时就会消失),这时前端就要从后台获取该文件倒计时的剩余时长。这是倒计时(定时任务)的用处1.
当后台的倒计时时长结束后,仍然没有获取到该文件的是被结果时、或者当后台的倒计时还没结束,获取到了文件识别结果,那么就要改变redis中该文件的状态,并通过websocket将其推动到前端。这时倒计时(定时)的用处2
那么定时任务怎么写呢,有哪几种方法,各种方法的有什么优缺点吗?(下面是来自其它人博客)
Java提供Timer和ScheduledThreadPoolExecutor两个类实现定时任务,其中Timer简单易用,但所有任务都是由同一个线程来调度,任务串行执行,任务之间存在互相干扰,一是前一个任务的延迟会导致后面的任务延迟,二是前一个任务异常导致后面的任务不再执行,三是Timer执行周期任务时依赖系统时间,如果当前系统时间发生变化,执行行为也会出现变化。
鉴于Timer的缺陷,Java 5提供了ScheduledThreadPoolExecutor实现定时任务,每个任务由线程池中一个线程去执行,任务并发执行,且相互之间不会受到干扰。此外,ScheduledExecutorService是基于时间延迟,不会由于系统时间的改变发生执行变化。但ScheduledThreadPoolExecutor要在某个时间点开始执行任务没有Timer方便,需要先计算出和执行时间点的时间差,然后设置第一次启动的延时。
综上,对于复杂的调度,最好是使用开源软件,如Quartz。java培训机构排名对于普通的周期性任务,使用ScheduledThreadPoolExecutor就可以满足要求,但使用ScheduledThreadPoolExecutor时,必须注意两点:
1. 一定要使用try{}catch(Throwable t){}捕获所有可能的异常,因为ScheduledThreadPoolExecutor会在任务执行遇到异常时取消后续执行。
2. 注意scheduleAtFixedRate与scheduleWithFixedDelay的区别,scheduleAtFixedRate是上一个任务开始执行之后延迟设定时间再执行,是从上一个任务开始时计时,但对于运行时长超过延迟时长的任务,会等上一个任务执行完之后,下一个任务才开始执行,此时,延时没有任何意义。而scheduleWithFixedDelay是在上一个任务结束执行之后延迟设定时间再执行,是从上一个任务结束时开始计算。
总和本次业务需求,应该选用ScheduledThreadPoolExecutor来处理。