在前面说了两种处理方式以后,下面介绍一种最近研究jdk无意发现的一个定时任务处理器。ScheduledExecutorService和Runnable接口配合实现定时任务的方案。这是在学习多线程的时候,发现的一种实现技术。对于类的使用方法,这里不再赘述。也是直接把代码弄上来。然后再分析。
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPools {
ScheduledExecutorService ses = Executors.newScheduledThreadPool(5);
class PrintThreadAsRate implements Runnable{
public void run() {
System.out.println("我是以固定频率运行的" +":"+System.currentTimeMillis()+":ThreadId"+Thread.currentThread().getId());
try {
//表示该任务需要1.5s才能完成。
Thread.currentThread().sleep(1500);
} catch (InterruptedException e) {
}
}
}
class PrintThreadAsDelay implements Runnable{
private boolean flag = false;
public void run() {
System.out.println("固定延迟运行"+System.currentTimeMillis()+":ThreadId"+Thread.currentThread().getId());
try {
//延迟代表该任务运行时间需要2s
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
int start = 0;
public void exeTask(int count){
for(;start < count; start++){
//以固定频率运行。
ses.scheduleAtFixedRate(new PrintThreadAsRate(), 1000,1*1000,TimeUnit.MILLISECONDS);
//以固定间隔运行。
ses.scheduleWithFixedDelay(new PrintThreadAsDelay(), 1000,1*1000,TimeUnit.MILLISECONDS);
}
//由于我使用junit测试,所以这里线程等待,以保证运行,如果使用main方法测试,不需要线程睡眠等待。
try {
Thread.currentThread().sleep(1000*60*60);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//我是以固定频率运行的:1408714479402:ThreadId10
//固定延迟运行1408714479403:ThreadId11
//我是以固定频率运行的:1408714480903:ThreadId10
//固定延迟运行1408714482404:ThreadId12
//我是以固定频率运行的:1408714482404:ThreadId11
//我是以固定频率运行的:1408714483905:ThreadId11
//固定延迟运行1408714485405:ThreadId12
//我是以固定频率运行的:1408714485406:ThreadId14
--------------------------------------------------------------------------------------------------------------------------------------------
代码有注释,具体的就不细说了,下面分析一下结果。由于原始数据比较乱。我们先将其整理一下。
//我是以固定频率运行的:1408714479402:ThreadId10
//我是以固定频率运行的:1408714480903:ThreadId10
//我是以固定频率运行的:1408714482404:ThreadId11
//我是以固定频率运行的:1408714483905:ThreadId11
//我是以固定频率运行的:1408714485406:ThreadId14
//固定延迟运行1408714479403:ThreadId11
//固定延迟运行1408714482404:ThreadId12
//固定延迟运行1408714485405:ThreadId12
整理完毕,我们发现以固定频率运行的任务,我们虽然设置的是一秒钟运行一次,但是实际的运行间隔确实1.5s才运行一次。
而以固定延迟运行的任务,虽然设置的是1s执行一次,但实际上却是3s才执行一次。
我们在这里可以看出来,与Timmer相比,他们是相同的,即每个任务执行完毕后,才会执行下一次任务。不会让任务重叠执行。
再看上面的线程分配。
在Timmer类中,所有的任务在同一个线程里执行。非常的不稳定。容易出问题。
在线程实现方式上,我们为每个任务分配一个线程。如果任务执行过程中出错,并且处置不当,也很可能会挂掉。
再观察我们本文中的实现,任务的定时执行,是由线程池来分配资源。每次执行任务的线程是随机的。即使这次执行不成功,也不会影响下次执行。即使使执行线程挂掉了,线程池也会自己补充一个,不会对任务执行造成影响。
所以,如果jdk版本支持,最好还是用这种方法来实现。
好了,关于定时任务的处理,三篇博客已经全部发完了。