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线程能否合并?*/