HZhoog

  :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

本人在写业务逻辑的时候,需要用到定时器,例如规定某条任务需要在什么时候进行运行,重复执行的间隔是多少,虽然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接口以便使其更好的具备扩展性。

 

posted on 2013-02-01 16:27  HZhoog  阅读(388)  评论(0编辑  收藏  举报