newCachedThreadPool如何重用线程?

时间:2014-05-13 20:36:26

标签: java multithreading threadpool executorservice threadpoolexecutor

我想问一下Zeller一年多前发布的同一个问题的更多细节......

javadoc表示Executors.newCachedThreadPool返回的服务重用了线程。这怎么可能?

我知道如何在内部设置队列结构,我不知道它是如何重用队列中的线程的。

我见过的所有示例都让开发人员创建了一个线程实例并通过"执行"方法

例如......

ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {            
  Runnable worker = new WorkerThread(i);  //will create 10 instances          
  executor.execute(worker);          
} 

我理解线程池可以轻松管理每个线程的生命周期,但同样,我看不到任何方法,也没有能力访问或重新启动池中的任何线程。

在上面的例子中,我希望每个线程都可以由线程池启动,运行,终止和处理,但永远不会重复使用。

消息传递系统将是您需要的地方的一个示例。假设你有一个onMessage处理程序,并且你想重用池中的一个线程来处理它,所以我希望像...这样的方法...

worker = executor.getIdleThread;
worker.setData(message);
executor.resubmit(worker);          

或者让ExecutorService充当工厂类并让它返回一个线程实例,在内部它决定创建一个新实例或重用旧实例。

ExecutorService executor = Executors.newCachedThreadPool(WorkerThread);
Runnable worker = executor.getThread;
worker.setData(message);

所以我错过了一些东西。这可能是一件简单的事情,但是我在下午阅读了教程和示例,但仍然没有想到它。有人可以对这个问题有所了解吗?

2 个答案:

答案 0 :(得分:2)

  

我了解线程池可以轻松管理生命周期   每个线程,但再次,我看到没有方法,也没有访问或   重启池中的任何线程。

线程的管理是在内部完成的。 ExecutorService界面仅提供外部可见的方法。

javadoc of newCachedThreadPool只是陈述

  

创建一个线程池,根据需要创建新线程,但是会   在先前构造的线程可用时重用它们。 [...] 要执行的调用将重用   先前构造的线程(如果可用)。如果没有现有线程   可用时,将创建一个新线程并将其添加到池中。主题   未使用60秒的任务将被终止并删除   从缓存。因此,一个长时间闲置的游泳池将会   不消耗任何资源。 [...]

这就是你得到的保证。如果您想知道它是如何实现的,您可以查看源代码,特别是ThreadPoolExecutor的代码。基本上,空闲线程将在一段时间后不执行任务后终止。

答案 1 :(得分:2)

我很好奇这是怎么可能的,因为线程无法重启,所以我分析了ThreadPoolExecutor的代码,这是你通过静态获得的所有ThreadPool ExecutorService的实现构造

首先,正如在另一个答案中所述,你不使用Threads,但在ThreadPools中使用Runnables,因为这会破坏目的。所以这里详细解释了ExecutorService如何重用Threads:

您通常会在submit()内添加一个Runnable,内部调用execute()方法。基本上,这会将runnable添加到队列中,如果没有工作ATM,则添加一个Worker

public void execute(Runnable command) {
        ...
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reje
ct(command);
    }

执行程序维护一堆Worker(内部类ThreadPoolExecutor)。它有你提交的runnable和一个Thread,它将通过你可能设置的ThreadFactory创建,或者只是一个默认的; Worker本身也是一个Runnable,用于从工厂创建Thread

private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
...
   Worker(Runnable firstTask) {
     this.firstTask = firstTask;
     this.thread = getThreadFactory().newThread(this);
   }

   public void run() {
      runWorker(this);
   }
...
}

添加工人时,它会被启动

private boolean addWorker(Runnable firstTask, boolean core) {
    ...
    Worker w = new Worker(firstTask);
    Thread t = w.thread;
    ...
    t.start();
    ...
    return true;
}

runWorker()方法在循环中运行并使用getTask()获取您提交的可在workingQueue中排队的runnables,并在getTask unitl等待超时发生。

   final void runWorker(Worker w) {
        Runnable task = w.firstTask;
        w.firstTask = null;
        boolean completedAbruptly = true;
        try {
            while (task != null || (task = getTask()) != null) {
                w.lock();
                clearInterruptsForTaskRun();
                try {
                    beforeExecute(w.thread, task);
                    Throwable thrown = null;
                    try {
                        task.run();
                    } catch (RuntimeException x) {
                    ...
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

这是getTask()方法

private Runnable getTask() {
   ...
        try {
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            ..
        } catch (InterruptedException retry) {
            ...
        }
    }
}

tl; dr 所以基本上Threadpool维护在循环中运行的工作线程并执行阻塞队列给出的runnables。工作人员将因需求而被创建和销毁(不再执行任务,工作人员将结束;如果没有自由工作人员,则&lt; maxPoolSize然后创建新工作人员)。我也不会称它为“#34;重复使用&#34;更多的线程将被用作执行所有runnables的looper。