java—使用threadpoolexecutor缩放maxpoolsize;为什么池不动态地增加其大小?

gojuced7  于 2021-06-27  发布在  Java
关注(0)|答案(1)|浏览(472)

作为初学者,我正在学习java中的线程和并发包,并且我已经阅读了有关threadpoolexecutor的文档,以了解它们之间的区别 getPoolSize() , getCorePoolSize() , getMaxPoolSize() 并试图在代码中实现同样的功能。
一点背景
据我所知, Executors.newFixedThreadPool(3) 创建一个corepoolsize=3的池,当我们继续通过池执行任务时,线程将被创建到3,然后当基础队列大小达到100并且仍然提交新任务时,这就是maxpoolsize进入图片的地方,线程被缩放到从corepoolsize现在达到maxpoolsize。

public class Test {

    static ThreadPoolExecutor pool=(ThreadPoolExecutor)Executors.newFixedThreadPool(3);

    public static void main(String k[]) throws InterruptedException{
        BlockingQueue<Runnable> queue=pool.getQueue();
        pool.execute(()->{
            for(int b=0;b<10;b++)
                System.out.println("Hello "+b);
        });
        pool.execute(()->{
            for(int b=0;b<10;b++)
                System.out.println("Hello "+b);
        });
        pool.setMaximumPoolSize(10);  //Setting maxPoolSize

     for(int j=0;j<20000;j++)       
        pool.execute(()->{
            for(int b=0;b<100;b++){
                System.out.println("Hello "+b);
            System.out.println("Queue size "+queue.size()+" "+"and pool size "+pool.getPoolSize()); 
        }
    });
 }

当执行上述程序时,我可以看到队列大小达到b/w 12000-20000,如果是这样的话 getPoolSize() 必须打印大于corepoolsize的值,因为maxpoolsize设置为10,但每次只打印3(即corepoolsize),为什么会发生这种情况?正如我们所期望的,它可以扩展到maxpoolsize。

5uzkadbs

5uzkadbs1#

这个 Executors.newFixedThreadPool 返回一个 ExecutorService ; 一个接口,它不公开(可能是很好的理由)这样的方法 setMaximumPoolSize 以及 setCorePoolSize .
如果创建类型为 Executors.newFixedThreadPool ,此池在应用程序的生存期内应保持固定。如果您想要一个可以相应地调整大小的池,那么应该使用 Executors.newCachedThreadPool() 相反。
据我所知,executors.newfixedthreadpool(3)创建了一个corepoolsize-3(…)的池
看执行 newFixedThreadPool 可以看出:

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}

所以当你经过的时候 3Executors.newFixedThreadPool 构造函数,设置 corePoolSize 以及 maximumPoolSize3 .
(…)当我们继续通过池执行任务时,线程将被创建到3,然后当基础队列大小达到100并且仍然提交新任务时,这就是maxpoolsize进入图片的地方,线程被缩放到从corepoolsize现在达到maxpoolsize。
实际上,这不是很准确,但我稍后会详细解释。现在阅读 Executors.newFixedThreadPool 它指出:
创建一个线程池,该线程池重用在共享无边界队列上运行的固定数量的线程。在任何时候,线程最多都是活动的处理任务。如果在所有线程都处于活动状态时提交其他任务,它们将在队列中等待,直到有线程可用。
所以池没有伸缩性(除非您显式地这样做)。
当执行上述程序时,我可以看到队列大小达到b/w 12000-20000,如果是这种情况,那么getpoolsize()必须打印大于corepoolsize的值,因为maxpoolsize设置为10,但是每次它只打印3(这就是corepoolsize)为什么会发生这种情况?正如我们所期望的,它可以扩展到maxpoolsize。
不,这不准确,如果你打印 pool.getMaximumPoolSize() 它会回来的 10 如预期,呼叫 pool.setMaximumPoolSize(10); 不会更改corepoolsize大小。但是,如果你这样做 pool.setCorePoolSize(10); 您将增加游泳池以处理 10 同时执行线程。
这个 this.maximumPoolSize 它只定义池应同时处理的线程数的上限,不改变池的当前大小。
为什么池不动态地增加其大小?
再深入一点 newFixedThreadPool 实现时,可以看到池是用任务队列初始化的 new LinkedBlockingQueue<Runnable>() 大小等于 Integer.MAX_VALUE . 看看这个方法 execute 在评论中可以看到以下内容:

/*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */

如果仔细阅读第2点和第3点,可以推断只有当任务不能添加到队列时,池才会创建比corepoolsize指定的线程更多的线程。自从 Executors.newFixedThreadPool 使用队列 Integer.MAX_VALUE 除非显式设置 corePoolSizepool.setCorePoolSize .
所有这些都是不必关心的实现细节。因此,为什么 Executors 接口不公开方法,例如 setMaximumPoolSize .
从threadpoolexecutor文档中可以看到:
核心和最大池大小
threadpoolexecutor将根据corepoolsize(请参阅getcorepoolsize())和maximumpoolsize(请参阅getmaximumpoolsize())设置的边界自动调整池大小(请参阅getpoolsize())。在方法execute(java.lang.runnable)中提交新任务时,如果运行的线程少于corepoolsize,则会创建一个新线程来处理请求,即使其他工作线程处于空闲状态。如果运行的线程多于corepoolsize,但少于maximumpoolsize,则仅当队列已满时才会创建新线程。通过将corepoolsize和maximumpoolsize设置相同,可以创建固定大小的线程池。通过将maximumpoolsize设置为一个基本上没有边界的值,例如integer.max\u value,您可以允许池容纳任意数量的并发任务。最典型的是,核心池和最大池大小仅在构造时设置,但也可以使用setcorepoolsize(int)和setmaximumpoolsize(int)动态更改。
这基本上证实了池没有动态更新其大小的原因。

相关问题