执行程序未按预期处理任务

10

如果我运行长时间的任务,执行程序在第一个任务没有完成时不会启动新线程。请问有谁能帮我理解为什么会这样,以及如何解决?

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.junit.Test;

public class TestExecutor {

    @Test
    public void test() throws InterruptedException {
        ExecutorService checkTasksExecutorService = new ThreadPoolExecutor(1, 10,
                100000, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());

        for (int i = 0; i < 20; i++) {
            checkTasksExecutorService.execute(new Runnable() {

                public  void run(){
                    try {
                        System.out.println(Thread.currentThread().getName() + "   running!");
                        Thread.sleep(10000);
                    } catch (Exception e) {
                    }

                }
            });
        }

        Thread.sleep(1000000);
    }
}
3个回答

8
这可以通过文档解决: 当在方法execute(java.lang.Runnable)中提交新任务,且运行的线程少于corePoolSize时,即使其他工作线程处于空闲状态,也会创建一个新线程来处理请求。如果正在运行的线程数大于corePoolSize但小于maximumPoolSize,则只有在队列已满的情况下才会创建新线程。 因此,要实现所需的行为,可以增加corePoolSize或为执行器服务提供不可增长的队列,如下所示:
ExecutorService checkTasksExecutorService = new ThreadPoolExecutor(1, 20,
    100000, TimeUnit.MILLISECONDS,
    new SynchronousQueue<Runnable>());

4

这种行为是由ThreadPoolExecutor内部逻辑引起的,如果向队列提供任务失败,则会添加新线程。您的队列没有边界,因此实际上意味着我们永远不会增长超过核心池大小并达到最大池大小。

试试下面的示例,以查看差异:

   ExecutorService checkTasksExecutorService = new ThreadPoolExecutor(1, 10,
                100000, TimeUnit.MILLISECONDS,
                new SynchronousQueue<Runnable>());

        for (int i = 0; i < 10; i++) {
            checkTasksExecutorService.execute(new Runnable() {

                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName() + "   running!");
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
            });
        }

        //Thread.sleep(1000000); //instead this use following

//stop accepting new tasks
        checkTasksExecutorService.shutdown();

while (!checkTasksExecutorService.isTerminated()) {
            Thread.sleep(100);
        }

4

ExecutorService.execute()的javadoc文档中写道:

在将来的某个时间执行给定的命令。命令可以在新线程、池化线程或调用线程中执行,由Executor实现自行决定

ThreadPoolExecutor.execute()的javadoc文档中也提到:

任务可以在新线程或现有线程中执行。

但是,在ThreadPoolExecutor.execute()的源代码注释中,原因被解释为:

如果任务可以成功排队,那么我们就完成了

稍后又说:

如果我们无法排队任务,则尝试添加新线程

由于您的队列是无界的,所以可以将更多的任务排队,因此不会创建新的线程来执行以下任务。

只有在无法将任务排队时才会创建更多线程。


你应该看一下ThreadPoolExecutor类的Javadoc :) - Marko Topolnik
@MarkoTopolnik,Javadoc并没有提供答案!请查看我的编辑。 - Bohemian
你怎么看?你看到我的报价了吗?它准确预测了会发生什么,以及如何更改以修复它。 - Marko Topolnik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接