首页 > 解决方案 > 执行器服务:它如何充当线程池的看门狗?

问题描述

我想了解它如何ExecutorService充当它创建的线程池的看门狗。

基本上,据我了解,ExecutorService它只是一个对象,它不是创建其他线程的“线程或进程”。

通常,对于ThreadPoolExecutor

threadPoolExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
// Now, requesting Executor Service to "execute" each submitted Tasks.
threadPoolExecutor.execute(runnable);

同样对于ScheduleThreadPoolExecutor

scheduledThreadPool = Executors.newSingleThreadScheduledExecutor(threadFactory);
scheduledThreadPool.scheduleAtFixedRate(runnable, 2000, 3000, TimeUnit.MILLISECONDS);

本质上,它们只是对象,它们如何能够,例如,“如果线程死亡则重新启动线程”。

我无法理解这一点,例如,如果ScheduledThreadPoolExecutor我们为定期操作调用一次方法,之后,该对象如何能够管理线程。

我确实查看了代码,我仍然对对象如何管理这一切有疑问?(创建线程池,将作业提交到队列,重新启动线程池中的线程等)

标签: javamultithreadingexecutorservicethreadpoolexecutorscheduledexecutorservice

解决方案


您应该更好地查看代码。实际上,大多数执行程序都有一个私有嵌套类,它封装了您的Runnable并在线程内对其进行管理。

Executors.newSingleThreadScheduledExecutor只需创建一个带有一个线程的ScheduledThreadPoolExecutor 。然后当你推送一个任务时,它会创建一个ScheduledFutureTask(也封装在一个RunnableScheduledFuture中)并必要时创建一个线程。

scheduleAtFixedRate

public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                              long initialDelay,
                                              long period,
                                              TimeUnit unit) {
    ...
    RunnableScheduledFuture<?> t = decorateTask(command,
                                                new ScheduledFutureTask<Object>(command,
                                                                null,
                                                                triggerTime,
                                                                unit.toNanos(period)));
    delayedExecute(t);
    return t;
}

延迟执行

private void delayedExecute(Runnable command) {
    if (isShutdown()) { // handling the cancellation 
        reject(command);
        return;
    }

    if (getPoolSize() < getCorePoolSize()) // increase number of thread if necessary
        prestartCoreThread();
    super.getQueue().add(command); // queue the task to be processed a soon as a task is finished
}

入队后,executor会一一出队(单线程executor的情况下,一个线程的线程池),最终会创建一个Thread ,代码中也称为worker。它将调用先前入队任务的 run() 方法:

ScheduledFutureTask.run

public void run() {
    if (isPeriodic())
        runPeriodic();
    else
        ScheduledFutureTask.super.run(); // just call run() of your Runnable
}

假设我们之前使用scheduleAtFixedRate提交了一个任务,该任务将被认为是周期性的,并且将调用 runPeriodic 方法:

ScheduledFutureTask.runPeriodic

private void runPeriodic() {
    boolean ok = ScheduledFutureTask.super.runAndReset(); // call run() from your Runnable
    boolean down = isShutdown();
    // Reschedule if not cancelled and not shutdown or policy allows
    if (ok && (!down ||
           (getContinueExistingPeriodicTasksAfterShutdownPolicy() && !isTerminating()))) {
        long p = period;
        if (p > 0)
            time += p;
        else
            time = now() - p;
        ScheduledThreadPoolExecutor.super.getQueue().add((Runnable) this);
    }
    // This might have been the final executed delayed
    // task.  Wake up threads to check.
    else if (down)
        interruptIdleWorkers();
}

这让您了解魔术是如何发生的。大多数“看门狗”的工作都发生在线程内部,他们自己管理。执行器的工作是确保它的队列总是空的,并在线程上调度和创建任务。由于 Java 的嵌套类的可能性,任务的行为然后通过直接访问 Executor 由它们自己处理。


推荐阅读