import java.util.Collections;
public class Test {
public void test() {
SScheduleExecutor scheduledThreadpool = new SScheduleExecutor();
System.out.println("Main test:time stamp = "+System.currentTimeMillis()/1000); /*显示以秒为单位*/
scheduledThreadpool.submit(new NormalWork(), 2000); /*以毫秒为单位*/
scheduledThreadpool.submit(new LoopWork(), 3000, 6000);
}
private class LoopWork implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("LoopWork,time stamp = "+System.currentTimeMillis()/1000);
}
}
private class NormalWork implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("NormalWork,time stamp = "+System.currentTimeMillis()/1000);
}
}
}
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
public abstract class DelayTask implements Delayed{
protected Runnable command = null;
protected long iniDelay = -1; /*in milliseconds*/
public DelayTask() {
}
public Runnable getTask() {
return command;
}
@Override
/*返回:
* 负值:当前对象小于输入对象
* zero:当前对象等于输入对象
* 正值:当前对象大于输入对象*/
public int compareTo(Delayed o) {
// TODO Auto-generated method stub
long defference = iniDelay - o.getDelay(TimeUnit.MILLISECONDS);
return (defference < 0) ? -1 : (defference > 0) ? 1 : 0;
}
}
public class DelayTaskFactory {
public DelayTask createDelayTask(Runnable command,long iniDelay) {
return new NormalDelayTask(command,iniDelay);
}
public DelayTask createDelayTask(Runnable command,long iniDelay,long period) {
return new LoopTask(command, iniDelay, period);
}
}
import java.util.concurrent.TimeUnit;
public class LoopTask extends DelayTask{
private long period = -1;
private long periodTimeStamp = -1;
private boolean isFirstRun = true; /*第一次执行后置为false*/
public LoopTask(Runnable command,long iniDelay,long period) {
super();
this.command = command;
this.iniDelay = System.currentTimeMillis()+iniDelay;
this.period = period;
}
@Override
public long getDelay(TimeUnit unit) {
// TODO Auto-generated method stub
if( false == isFirstRun && -1 != period ) {
/*周期任务,非第一次执行,返回period*/
return periodTimeStamp-System.currentTimeMillis();
}
return iniDelay-System.currentTimeMillis();
}
private void setFirstRunFalse() { isFirstRun = false; };
private void setFirstRunTrue() { isFirstRun = true; }
public void resetTask() {
setFirstRunFalse();
periodTimeStamp = System.currentTimeMillis()+period;
}
}
import java.util.concurrent.TimeUnit;
public class NormalDelayTask extends DelayTask{
public NormalDelayTask(Runnable command,long iniDelay) { /*暂时默认以毫秒为单位*/
super();
this.command = command;
this.iniDelay = System.currentTimeMillis()+iniDelay;
}
@Override
public long getDelay(TimeUnit unit) { /*暂时默认以毫秒为单位*/
// TODO Auto-generated method stub
return iniDelay-System.currentTimeMillis();
}
}
public interface SExecutorService {
public void submit(Runnable r,long delay,long period);
public void submit(Runnable r,long delay);
}
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SScheduleExecutor implements SExecutorService{
/*内部保存一个线程池,用来产生consumer,线程池暂定无界;producer则是每次调用submit,SScheduleExecutor自己;
* 内部保存一个DelayQueue*/
private ExecutorService threadpool = Executors.newCachedThreadPool();
private BlockingQueue<Delayed> delayQueue = new DelayQueue<Delayed>();
private DelayTaskFactory taskFac = new DelayTaskFactory();
private WorkerThreadFactory threadFac = new WorkerThreadFactory();
private void addWorkerThread(DelayTask task) {
try {
delayQueue.put(task);
/*新创建一个工作线程,执行对DelayQueue的take操作*/
threadFac.createWorkerThread().start();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void submit(Runnable r,long delay,long period) {
// TODO Auto-generated method stub
DelayTask task = taskFac.createDelayTask(r, delay, period);
addWorkerThread(task);
}
@Override
public void submit(Runnable r, long delay) {
// TODO Auto-generated method stub
DelayTask task = taskFac.createDelayTask(r, delay);
addWorkerThread(task);
}
/*工作线程,每提交一个任务,分配一个工作线程来take此任务,工作线程从DelayQueue中取出任务后,再执行任务*/
private class WorkerThread extends Thread{
public WorkerThread() {
}
@Override
public void run() {
// TODO Auto-generated method stub
/*对DelayQueue执行take操作,获取成功后,将task的是否第一次执行置为false(先判断是否looptask),
* 如果是looptask,需要将此task再put到DelayQueue,执行完这些操作后,给task分配一个线程执行。*/
DelayTask task = null;
do {
task = (DelayTask)delayQueue.poll(); /*返回值若为null,表示queue里面没有数据*/
if( null != task ) {
if( task instanceof LoopTask ) {
((LoopTask) task).resetTask();
addWorkerThread(task);
}
threadpool.execute(task.getTask());
}
}while(null == task);
}
}
private class WorkerThreadFactory {
public WorkerThread createWorkerThread() {
return new WorkerThread();
}
}
}
/*用DelayQueue模拟了一个ScheduledExecutorService。
* 要点:
* 1、Delayed接口的两个方法的实现
* 2、每个DelayTask配置一个工作线程,用来将DelayTask从DelayQueue中取出,执行,或者重设后执行
* 3、LoopTask的处理,initDelay与period的区别处理
* 4、getDelay方法,返回的是动态值,其单位与入参的TimeUnit匹配,具体匹配方式在方法内部实现
*
* 思考:
* 1、priorityQueue使用compareTo方法将DelayTask排序
* 2、DelayQueue使用getDelay方法,根据返回值让工作线程delay,直到超时时间到
* 3、如果将工作线程也交给线程池分配,是否可降低开销?
* 4、工作线程与DelayTask线程能否合并?*/