ScheduledThreadPoolExecutor scheduleWithFixedDelay和“紧急”执行

时间:2009-09-09 19:13:47

标签: java

我有以下问题,标准库无法很好地解决,我想知道是否有人在那里看到了另一个库而不是可以做到这一点所以我不需要一起破解自定义解决方案。我有一个当前使用scheduleWithFixedDelay()在线程池上调度的任务,我需要修改代码来处理与异步事件相关的任务“紧急”执行的请求。因此,如果任务计划在执行之间延迟5分钟,并且在最后一次完成执行后2分钟发生事件,我想立即执行任务,然后在完成后等待5分钟。在再次运行之前紧急执行。现在我能想到的最好的解决方案是让事件处理程序在scheduleWithFixedDelay()返回的ScheduledFuture对象上调用cancel()并立即执行任务,然后在任务中设置一个标志,告诉它重新安排自己具有相同的延迟参数。这个功能是否已经可用,我只是遗漏了文档中的内容?

2 个答案:

答案 0 :(得分:6)

如果您使用ScheduledThreadPoolExecutor,则有一个方法decorateTask(实际上有两个,对于Runnable和Callable任务),您可以覆盖这些方法以存储对某个任务的引用。

当您需要紧急执行时,只需在该引用上调用run()即可使其运行并以相同的延迟重新安排。

快速入侵企图:

public class UrgentScheduledThreadPoolExecutor extends
        ScheduledThreadPoolExecutor {
    RunnableScheduledFuture scheduledTask;

    public UrgentScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize);
    }

    @Override
    protected  RunnableScheduledFuture decorateTask(Runnable runnable,
            RunnableScheduledFuture task) {
        scheduledTask = task;
        return super.decorateTask(runnable, task);
    }

    public void runUrgently() {
        this.scheduledTask.run();
    }
}

可以这样使用:

public class UrgentExecutionTest {

    public static void main(String[] args) throws Exception {
        UrgentScheduledThreadPoolExecutor pool = new UrgentScheduledThreadPoolExecutor(5);

        pool.scheduleWithFixedDelay(new Runnable() {
            SimpleDateFormat format = new SimpleDateFormat("ss"); 

            @Override
            public void run() {
                System.out.println(format.format(new Date()));
            }
        }, 0, 2L, TimeUnit.SECONDS);
        Thread.sleep(7000);
        pool.runUrgently();
        pool.awaitTermination(600, TimeUnit.SECONDS);
    }
}

并生成以下输出: 06 08 10 的 11 13 15

答案 1 :(得分:0)

根据要求(soz,匆忙)我的EventBasedExecutor

警告:目前仅适用于定期运行中安排的任务。您可以更改代码来处理所有任务,我到目前为止还没有,因为我只有定期运行的任务。我也在一个单元线程的线程池中运行它(我只需要一个预定的运行程序线程,它每隔X秒一次在一个专用线程中运行)

我们走了:

public class EventBasedExecutor extends ScheduledThreadPoolExecutor implements EventBasedExecutorService {

    private List<RunnableScheduledFuture<?>> workers = new ArrayList<>();

    private int index;

    public EventBasedExecutor(int corePoolSize) {
        super(corePoolSize,  new ThreadFactoryBuilder().setDaemon(true).setNameFormat("message-sender-%d").build());
    }

    @Override
    protected <V> RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task) {
        if(!workers.contains(runnable)) {
            workers.add(task);
        }
        return super.decorateTask(runnable, task);
    }

    @Override
    public void executeEarly() {
        if(index >= workers.size()) {
            index = 0;
        }

        if(workers.size() == 0) {
            return;
        }

        RunnableScheduledFuture<?> runnableScheduledFuture = workers.get(index);
        index ++;
        execute(runnableScheduledFuture);
        System.out.println("Executing");
    }


    public static void main(String[] args) throws InterruptedException {
        EventBasedExecutor executor = new EventBasedExecutor(10);

        long currentTimeMillis = System.currentTimeMillis();

        // this will never run
        executor.scheduleAtFixedRate(() -> {
            System.out.println("hello");
        }, 5000, 5000, TimeUnit.HOURS);

        executor.executeEarly();

        System.out.println("Run after: " + (System.currentTimeMillis() - currentTimeMillis));
    }

}

这将在专用工作线程中执行任务。

它将打印:

Executing
hello
Run after: 39

玩得很开心:)

artur