本人在写业务逻辑的时候,需要用到定时器,例如规定某条任务需要在什么时候进行运行,重复执行的间隔是多少,虽然java本身就已经有提供,但是自己觉得应该不难,所以尝试自己实现。
首先是线程是的控制类。ScheduledManager类负责控制所有的子任务,包括启动,取消子任务。
ScheduledEntry类是子任务实体类。可定义开始执行时间,延迟执行时间,间隔时间,结束时间等。
此类继承Runnable接口.
ScheduledManager主要代码如下:
View Code
/** * 未启动的线程 */ private volatile static ConcurrentHashMap<Long,RunEntry> runnables = new ConcurrentHashMap<Long, RunEntry>(); /** * 已启动线程 */ private volatile static ConcurrentHashMap<Long,RunEntry> hasRunnables = new ConcurrentHashMap<Long,RunEntry>(); /** * 需删除的线程实体Id */ private volatile static List<Long> rmIds = new ArrayList<Long>(); /**最大线程数*/ private static int maxThread = 10; /** * 添加子任务 * @param able * @return */ public static int addRun(RunEntry able){ if(runnables.size() >= maxThread){ return -1; } runnables.put(able.getRunId(), able); return 1; } public static RunEntry getHasRunEntry(int runId){ return hasRunnables.get(runId); } /** * 启动主线程 */ public void run(){ while(true){ if(runnables.size() <= 0){ try { sleep(1000); continue; } catch (InterruptedException e) { e.printStackTrace(); } } long currentTime = System.currentTimeMillis(); for(Entry<Long, RunEntry> entry : runnables.entrySet()){ /*达到开始时间启动线程*/ if(entry.getValue().getStartTime() <= currentTime){ new Thread(entry.getValue()).start(); hasRunnables.put(entry.getKey(),entry.getValue()); rmIds.add(entry.getKey()); } } if(rmIds.size() >0 ){ for(Long key : rmIds) runnables.remove(key); rmIds.clear(); } } } /** * 取消定时任务 * @param runId * @return */ public static int cancel(long runId){ RunEntry entry = hasRunnables.get(runId); if(entry != null){ entry.setFlag(false); hasRunnables.remove(runId); }else{ entry = runnables.get(runId); if(entry == null){ return 1; } entry.setFlag(false); runnables.remove(runId); } return 1; }
ScheduledEntry主要代码如下:
View Code
/**标记*/ private long runId; /**线程执行间期*/ private long interval; /**开始延迟时间*/ private long delay; /**开始时间*/ private long startTime; /**线程生命控制*/ private volatile boolean flag = true; /** * 结束时间 */ private long endTime; /** * 是否设置了结束时间 */ private boolean isSetEntTime = false; public RunEntry(long interval,long delay,boolean isSetEndTime){ this.runId = System.currentTimeMillis(); this.interval = interval; this.delay = delay; this.startTime = System.currentTimeMillis() + delay; this.isSetEntTime = isSetEndTime; } @Override public void run() { while(flag){ if(!flag)break; /*达到设定结束时间结束线程*/ if(isSetEntTime){ long current = System.currentTimeMillis(); if(endTime <= current) break; } /*根据自己的逻辑需要*/ try { Thread.sleep(interval); } catch (InterruptedException e) { e.printStackTrace(); } } }
本方法只是提供了一个实现思路,其性能不太好,应为如果队列中有任务,则会一直循环探测,造成性能的浪费,其更好的解决方式是对队列中所有的任务按启动时间远近来排序,最先启动的排在最前面,计算出所需时间,让主线程休眠,当有插入时重新计算一次,这样可避免资源的浪费,ScheduledEntry可进行封装,抽出run部分并实现Runnable接口以便使其更好的具备扩展性。