为什么ThreadPoolExecutor中的maxPoolSize什么都不做?

时间:2017-12-25 20:16:57

标签: java multithreading

ThreadPoolExecutor 类中,有一个maxPoolSize指定最大线程池大小。这意味着如果线程数小于该数量,则应立即执行池中的线程。但我发现事实并非如此。它实际上不能超越corePoolSize。我很迷惑。如果没有什么工作,maxPoolSize的目的是什么?这是我的测试程序:

我指定了corePoolSize = 2; maxPoolSize = 6;我创建了5个线程(Runnable)。我认为所有5个线程(Runnable)应该同时运行。但他们不是。其中只有两个正在运行,另外三个被搁置,直到前两个死亡。

我已经阅读了很多关于该主题的帖子。但没有人可以指导我让5个线程同时运行。

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

public class MyThreadPoolExecutorTest2
{
    private List<MyRunnable> myRunnables = new ArrayList<>();

    public static void main(String[] args)
    {
        new MyThreadPoolExecutorTest2().test();
    }

    public void test()
    {
        int poolSize = 2;
        int maxPoolSize = 6;
        int threadPoolKeepAliveTimeInSec = 30;
        ExecutorService threadPoolExecutor =
                new MySimpleThreadPoolExecutor(poolSize, maxPoolSize, threadPoolKeepAliveTimeInSec);
        int numOfThread = 5;
        System.out.println("Start thread pool test with corePoolSize=" + poolSize + ", maxPoolSize=" + maxPoolSize
                + ", actualThreads=" + numOfThread);
        for (int i = 0; i < numOfThread; i++)
        {
            MyRunnable tempRunnable = new MyRunnable(i + 1, "PoolTest" + (i + 1));
            myRunnables.add(tempRunnable);
            threadPoolExecutor.execute(tempRunnable);
        }
        System.out.println("********* wait for a while");
        try
        {
            Thread.sleep(20000);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }

        System.out.println("^^^^^^^^^^ shutdown them all");
        for (MyRunnable runnable : myRunnables)
        {
            runnable.shutdown();
        }
        System.out.println("Ended thread pool test.");
    }

    public class MyRunnable implements Runnable
    {
        private int id = 0;
        private String name = "";

        private boolean shutdown = false;

        public MyRunnable(int id, String name)
        {
            this.id = id;
            this.name = name;
        }

        @Override
        public void run()
        {
            System.out.println("++++ Starting Thread: " + id + ":" + name);
            while (!shutdown)
            {
                try
                {
                    Thread.sleep(200);
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
            System.out.println("---- Ended Thread: " + id + ":" + name);
        }

        public void shutdown()
        {
            shutdown = true;
        }
    }
}

class MySimpleThreadPoolExecutor extends ThreadPoolExecutor
{
    private static int peakActiveThreads = 0;
    private String taskInfo = "";

    public MySimpleThreadPoolExecutor(int nThreads, int maxThreads, int threadPoolKeepAliveTimeInSec)
    {
        super(nThreads, maxThreads, threadPoolKeepAliveTimeInSec * 1000L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
        System.out.println("MySimpleThreadPoolExecutor::MySimpleThreadPoolExecutor(), threadPoolSize=" + nThreads
                + ", maxThreadCount=" + maxThreads + ", threadPoolKeepAliveTimeInSec=" + threadPoolKeepAliveTimeInSec);
    }

    @Override
    public void beforeExecute(Thread t, Runnable r)
    {
        int activeCount = getActiveCount();
        if (MySimpleThreadPoolExecutor.peakActiveThreads < activeCount)
        {
            MySimpleThreadPoolExecutor.peakActiveThreads = activeCount;
        }
        taskInfo = r.toString();
        String msg =
                "BeforeE thread(name:id)::" + t.getName() + ":" + t.getId() + ", task::" + r.toString() + "\n"
                        + threadPoolInfoStr();
        System.out.println("ThreadInfo before, MySimpleThreadPoolExecutor::beforeExecute(), " + msg);
        super.beforeExecute(t, r);
    }

    @Override
    public void execute(Runnable command)
    {
        beforeExecute(Thread.currentThread(), command);
        super.execute(command);
    }

    public String threadPoolInfoStr()
    {
        return String.format("Thead: %s/%d\n[PoolSize/CorePoolSize] [%d/%d]\nActive: %d\nCompleted: %d\nTask: %d"
                + "\nisShutdown: %s\nisTerminated: %s\npeakActiveThreads: %d\nTaskInfo: %s\nQueueSize: %d", Thread
                .currentThread().getName(), Thread.currentThread().getId(), getPoolSize(), getCorePoolSize(),
                getActiveCount(), getCompletedTaskCount(), getTaskCount(), isShutdown(), isTerminated(),
                MySimpleThreadPoolExecutor.peakActiveThreads, taskInfo, getQueue().size());
    }
}

2 个答案:

答案 0 :(得分:4)

一旦队列已满,新线程将仅创建到maxPoolSize。在限制之前是在corePoolSize中定义的限制。

参考:http://www.bigsoft.co.uk/blog/index.php/2009/11/27/rules-of-a-threadpoolexecutor-pool-size

答案 1 :(得分:1)

只有在队列已满时才会添加更多线程。

由于LinkedBlockingQueue没有限制,因此永远不会满员。因此,池中线程的核心池大小永远不会超过。

使用TransferQueue或使用有界队列来解决此问题。