DelayQueue 實現簡單的定時任務

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/woshimike/article/details/54669572

今天聽qq羣裏面說了一個,用戶 可以自定義任務的場景,我首相想到的是 spring 定時任務,不過 想了下 這個 不夠靈活而且有一定的延遲。後來想到了

DelayQueue + 線程池 的想法,自己簡單做了下實現 。代碼如下 


package com.lyq.jsoup.delayqueue;


public enum MethodEnum {

    SEND_MESSAGE(0, "handlerSendMessage"),
    AUTO_BUY(1, "handlerAutoBuy");

    private int index;
    private String methodName;

    public static MethodEnum getMethodEnumByIndex(int index) {
        MethodEnum[] methodEnums = values();
        for (int i = 0; i < methodEnums.length; i++) {
            MethodEnum methodEnum = methodEnums[i];
            if (methodEnum.getIndex() == index) {
                return methodEnum;
            }
        }
        return null;
    }

    MethodEnum(int index, String methodName) {
        this.index = index;
        this.methodName = methodName;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }


}

這個類是一個枚舉類,用了模擬方法類型。



package com.lyq.jsoup.delayqueue;

import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

public class PersonalTask implements Delayed {
    private static int counter = 0;
    private int id = counter++;
    private long triggerTime;
    private MethodEnum methodEnum;

    public PersonalTask(long triggerTime, MethodEnum methodEnum) {
        this.triggerTime = triggerTime;
        this.methodEnum = methodEnum;
    }

    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(triggerTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
    }

    @Override
    public int compareTo(Delayed o) {
        PersonalTask that = (PersonalTask) o;
        if (triggerTime < that.triggerTime) return -1;
        if (triggerTime > that.triggerTime) return 1;
        return 0;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public long getTriggerTime() {
        return triggerTime;
    }

    public void setTriggerTime(long triggerTime) {
        this.triggerTime = triggerTime;
    }

    public MethodEnum getMethodEnum() {
        return methodEnum;
    }

    public void setMethodEnum(MethodEnum methodEnum) {
        this.methodEnum = methodEnum;
    }
}


這個類是 用戶自定義任務vo,這個類可以持久化到數據庫。



package com.lyq.jsoup.delayqueue;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.DelayQueue;

/**
 * Created by Administrator on 2017/1/22.
 */
public class PersonalCussumer implements Runnable {

    private DelayQueue<PersonalTask> tasks;

    public PersonalCussumer(DelayQueue<PersonalTask> tasks) {
        this.tasks = tasks;
    }

    @Override
    public void run() {
        while (!Thread.interrupted()) {
            try {
                PersonalTask task = tasks.take();
                if (null == task) {
                    continue;
                }
                handler(task);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Finished PersonalCussumer");
        }
    }

    private void handler(PersonalTask task) {
        try {
            Method method = this.getClass().getMethod(task.getMethodEnum().getMethodName(), PersonalTask.class);
            method.invoke(this, task);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public void handlerSendMessage(PersonalTask task) {
        System.out.println("id:" + task.getId() + "  start send message");
    }

    public void handlerAutoBuy(PersonalTask task) {
        System.out.println("id:" + task.getId() + "  start auto buy");
    }
}



這個類是,用戶自定義任務的處理邏輯,可以根據用戶的定製去做不同的處理 。



package com.lyq.jsoup.delayqueue;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Created by Administrator on 2017/1/22.
 */
public class ThreadPoolUtils {
    public static void main(String[] args){
        //存放任務處理的隊列
        DelayQueue<PersonalTask> delayQueue = new DelayQueue();

        //初始化線程池
        ArrayBlockingQueue<Runnable> arrayWorkQueue = new ArrayBlockingQueue(10);
        ExecutorService threadPool = new ThreadPoolExecutor(5,
                10,
                60L,
                TimeUnit.SECONDS,
                arrayWorkQueue,
                new ThreadPoolExecutor.AbortPolicy());

        //模擬10條數據 這裏可以是從數據庫裏面查詢出滿足條件的數據
        for (int i = 0;i<10;i++){
            delayQueue.put(getPersonalTask());
        }
        threadPool.execute(new PersonalCussumer(delayQueue));
        threadPool.shutdown();
        System.out.println(Thread.currentThread().getName());
    }

    public static PersonalTask getPersonalTask(){
        Random random = new Random();
        int randomAddMilliSenconds = random.nextInt(20);

        long triggerTime = System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(randomAddMilliSenconds, TimeUnit.SECONDS);

        int methodIndex = new Random().nextInt(2);
        MethodEnum methodEnum = MethodEnum.getMethodEnumByIndex(methodIndex);
        PersonalTask task = new PersonalTask(triggerTime,methodEnum);

        //調適語句 可以忽略
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(sdf.format(new Date(task.getTriggerTime())));

        return task;
    }
}



       核心處理邏輯,用線程池去消費隊列裏面的任務,現實項目中可以把 DelayQueue 做成全局 變量,如果 有用戶定製任務,持久化後就放進隊列中,等待處理。需要注意的是當服務器重啓的時候 需要初始化隊列裏面的數據。這就需要持久化中有處理狀態字段。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章