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

时间:2013-07-27 14:34:16

标签: java concurrency executor

如果我运行持久的任务,如果第一个任务没有完成,Executor永远不会启动新线程。有人可以帮我理解为什么以及如何解决这个问题?

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 个答案:

答案 0 :(得分:4)

这可以通过文档解决:

  

当在方法execute(java.lang.Runnable)中提交新任务且运行的线程少于corePoolSize时,即使其他工作线程处于空闲状态,也会创建一个新线程来处理该请求。如果有超过corePoolSize但少于maximumPoolSize个线程正在运行,则只有在队列已满

时才会创建一个新线程

因此,要实现所需的行为,请增加corePoolSize或为执行程序服务提供不可增长的队列,如下所示:

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

答案 1 :(得分:3)

此行为是由于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);
        }

答案 2 :(得分:3)

ExecutorService.execute()的javadoc说:

  

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

ThreadPoolExecutor.execute()的javadoc强化了这一点,其中说:

  

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

原因ThreadPoolExecutor.execute()的来源评论中有解释说明:

  

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

稍后

  

如果我们无法对任务进行排队,那么我们会尝试添加新线程

由于您的队列是无限制的,因此可以对其他任务进行排队,因此不会创建新线程来执行以下任务。

仅当任务无法排队时才会创建更多线程。