【问题标题】:why the maxPoolSize in the ThreadPoolExecutor do nothing? [duplicate]为什么 ThreadPoolExecutor 中的 maxPoolSize 什么都不做? [复制]
【发布时间】:2018-06-06 21:25:07
【问题描述】:

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

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

我已经阅读了很多关于该主题的帖子。但是没有人可以指导我让 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());
    }
}

【问题讨论】:

标签: java multithreading


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    仅当队列已满时才会添加更多线程。

    由于您的LinkedBlockingQueue 没有界限,它永远不会被填满。因此,池中的线程永远不会超过核心池大小。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-04-16
      • 1970-01-01
      • 1970-01-01
      • 2018-07-13
      • 2019-04-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多