如何知道Runnable计划重复执行

时间:2019-03-08 22:38:38

标签: java scheduledexecutorservice

我需要运行五个线程来每隔20秒从API重复获取数据,所以我使用了ScheduledExecutorService。

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);

for (int i = 0; i < 5; i++) {
    scheduler.scheduleWithFixedDelay(Constant.workerThread[i], 0, delay, TimeUnit.SECONDS);
}

我怎么知道(每次)执行五个线程的时间?

4 个答案:

答案 0 :(得分:2)

编辑:看来人们并没有真正理解代码段的想法。我将其设置为大胆,以便没有人再出现在我面前,从外部(而不是在shell_exec("php slow_request.php '".$parameter.”’ > /dev/null &"); lambda内部)管理内部ExecutorService,并在需要时采取适当的措施使其有序地关闭< / strong>。

您可以做的是管理一个预定的任务,然后在其中执行五个工作人员。

Callable

JavaDoc for final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5); scheduler.scheduleWithFixedDelay( () -> { final ExecutorService e = Executors.newFixedThreadPool(5); final CompletionService<?> cs = new ExecutorCompletionService<>(e); for (int i = 0; i < 5; i++) { // Constant.workerThread[i] is a Runnable cs.submit(Constant.workerThread[i], null); } for (int i = 0; i < 5; i++) { try { // Will block until a Future<?> result is available. // Doesn't matter which one, it will take the first available. cs.take(); } catch (final InterruptedException ignored) { // Ingore the exception, as we care only // about if all off them finished (abruptly or not) } } // All of them finished! e.shutdown(); }, 0, 20, TimeUnit.SECONDS));

  

使用提供的ExecutorCompletionService执行的CompletionService   任务。此类安排提交的任务完成后,   放在使用Executor可以访问的队列中。

JavaDoc for take

  

检索并删除代表下一个完成的ExecutorCompletionService#take   任务,等待是否还没有出现。

这必须加以改进,但是您应该明白这一点。

答案 1 :(得分:1)

我们运行Runnable个对象,而不是线程

线程没有被“执行”。

您应将Runnable传递给ScheduledExecutorService::scheduleAtFixdDelay。我对您的命名Constant.workerThread感到担心。您没有传递线程,而是传递了要在某个线程上运行的任务。您不必担心哪个线程运行什么Runnable任务。您根本不需要关心线程。处理要在线程上运行的任务是执行程序的工作,因此是名称。

您似乎缺少线程和任务的基本概念。毫不奇怪,因为它刚开始时是一个棘手的主题。我建议研究Oracle.com免费提供的有关线程和执行程序的Java教程。然后进行一些互联网搜索以了解更多信息。最终,您应该学习Brian Goetz等人的著作《 Java Concurrency In Practice》。

ScheduledFuture跟踪完成情况

因此,您将不会监视线程。而是专注于您的Runnable任务。要监视它们的状态,请通过调用ScheduledFuture来捕获scheduleAtFixedDelay对象返回。当前,您正在忽略那些返回的对象。

该计划的将来对象提供了一些方法来查看任务是否完成或取消。您也可以取消任务。

答案 2 :(得分:1)

如果您可以更改计划任务的源代码,则可以实现以下内容:

public class ScheduleExample {

    private static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);

    static abstract class RunnableWithNotification implements Runnable {

        @Override
        public final void run() {
            beforeRun();
            doRun();
            afterRun();
        }

        public abstract void doRun();

        public abstract void beforeRun();

        public abstract void afterRun();
    }

    public static void main(String... args) {

        long delay = 5;
        List<Runnable> tasks = Arrays.asList(
                newRunnableWithNotification(1),
                newRunnableWithNotification(2),
                newRunnableWithNotification(3),
                newRunnableWithNotification(4),
                newRunnableWithNotification(5));

        tasks.forEach(task -> scheduler.scheduleWithFixedDelay(task, 0, delay, TimeUnit.SECONDS));

    }

    private static Runnable newRunnableWithNotification(int i) {
        return new RunnableWithNotification() {
            @Override
            public void doRun() {
                System.out.println("Executing task " + i);
            }

            @Override
            public void beforeRun() {
                System.out.println("Before executing task " + i);
            }

            @Override
            public void afterRun() {
                System.out.println("After executed task " + i);
            }
        };
    }
}

答案 3 :(得分:0)

您可以设置一种执行映射。
关于每个可运行对象的执行状态的总是最新数据。 这是一个一般示例,因此您需要使其适应您的需求。

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Application { 
    // Your mocked runnables
    private static List<Runnable> workerRunnables = new ArrayList<>();
    // This will be the map with always updated values, get the map at[i]
    // will return if workerThread[i is running]
    private static Map<Integer, Boolean> executionMap = new ConcurrentHashMap<>();
    private static final int threadPoolSize = 5;

    public static void main(String[] args) {
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(threadPoolSize);

        for (int i = 0; i < threadPoolSize; i++) {
            int finalI = i;
            workerRunnables.add(() -> {
                try {
                    // Update the map, the runnable has started
                    executionMap.put(finalI, true);

                    // Simulating your API calls with different types of delay
                    Thread.sleep(3000);
                    if (finalI == 2) {
                        Thread.sleep(1000);
                    }

                    // Update the map, the runnable has finished
                    executionMap.put(finalI, false);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        workerRunnables.forEach(worker -> scheduler.scheduleWithFixedDelay(worker, 0, 2, TimeUnit.SECONDS));

        Executors.newCachedThreadPool().execute(new Runnable() {
            ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

            @Override
            public void run() {
                scheduler.scheduleWithFixedDelay(new Runnable() {
                    @Override
                    public void run() {
                        for (int i = 0; i < threadPoolSize; i++) {
                            System.out.println("Runnable number " + i +" is running: " + executionMap.get(i));
                        }
                    }
                }, 0, 2, TimeUnit.SECONDS);
            }
        });
    }
}