我读到ThreadPoolExecutor有线程池,这个池注定要降低创建新线程的成本(至少我以这种方式理解下面的短语):
When you send a task to the executor,it tries to use a pooled thread
for the execution of this task,to avoid continIoUs spawning of
threads. [Java 7 Concurrency Cookbook]
但是,据我所知,我们无法在Java中重启线程.
问题:ThreadPoolExecutor如何避免创建新线程?
解决方法
它非常简单 – 本质上线程睡眠,等待被任务唤醒 – 它们运行该任务然后再次睡眠.
public static void main(final String[] args) throws Exception { final BlockingQueue<Runnable> blockingQueue = new LinkedBlockingDeque<>(); final Thread t = new Thread(new Runnable() { @Override public void run() { while (true) { try { blockingQueue.take().run(); } catch (InterruptedException ex) { return; } } } }); t.start(); blockingQueue.add(new Runnable() { @Override public void run() { System.out.println("Task 1"); } }); blockingQueue.add(new Runnable() { @Override public void run() { System.out.println("Task 2"); } }); }
BlockingQueue会在空的时候阻塞它.当我添加一个项目时,当前被阻止的线程被唤醒,并且将执行任务(LinkedBlockingDeque是线程安全的).线程完成任务后,它会重新进入休眠状态.
ThreadPoolExecutor的JavaDoc详细描述了逻辑. ThreadPoolExecutor的所有构造函数都采用BlockingQueue< Runnable> – 这应该给你一个提示,因为逻辑是如何工作的.
注意:这与忙碌的等待不一样. BlockingQueue使用wait和notify来挂起和唤醒线程,这意味着池中的线程在没有处理任务时没有做任何工作.基于繁忙等待的方法不起作用,因为线程将阻止所有cpu核心,其轮询不允许程序继续(或至少严重损害它).