线程池大小一般设计成cpu多少倍为好?CPU性能详解

TheDisguiser 2020-05-31 12:28:47 java常见问答 4268

线程池的大小有时候会让人难以决定,所以通常会将线程池的大小设置成CPU的倍数,那问题就来了,一般线程池大小一般该设计成cpu的多少倍呢?下面一起来了解一下吧。

例:

package com.lc.concurrent;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class MyThreadPoolExecutor
{
    //最大可用的CPU核数
    public static final int PROCESSORS = Runtime.getRuntime()
        .availableProcessors();
    //线程最大的空闲存活时间,单位为秒
    public static final int KEEPALIVETIME = 60;
    //任务缓存队列长度
    public static final int BLOCKINGQUEUE_LENGTH = 500;
    public ThreadPoolExecutor createThreadPool()
    {
        return new ThreadPoolExecutor(PROCESSORS * 2, PROCESSORS * 4, KEEPALIVETIME, TimeUnit.SECONDS
            , new ArrayBlockingQueue < Runnable > (BLOCKINGQUEUE_LENGTH));
    }
}

以上面例子来说,池中总线程数是核心池线程数量两倍,只要确保当核心池有线程停止时,核心池外能有线程进入核心池即可。

我们关心的主要是核心池线程的数量该如何设置。线程中的任务最终是要交给CPU的线程去处理的,而CPU可同时处理线程数量大部分是CPU核数的两倍,在运行环境中CPU的核数我们可以通过Runtime.getRuntime().availableProcessors()

方法获取。理论上来说核心池线程数量应该是为Runtime.getRuntime().availableProcessors()*2,现在我们就来测试一下结果吧。

例:

package com.lc.concurrent;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ThreadPoolExecutor;
public class CreateThreads
{
    public synchronized static void main(String[] args)
    {
        System.out.println(MyThreadPoolExecutor.PROCESSORS);
        new CreateThreads()
            .test();
    }
    public synchronized void test()
    {
        ThreadPoolExecutor threadPoolExecutor = new MyThreadPoolExecutor()
            .createThreadPool();
        for (int i = 0; i <= 100; i++)
        {
            MyTask myTask = new MyTask(i);
            threadPoolExecutor.execute(myTask);
        }
        threadPoolExecutor.shutdown();
    }
}
class MyTask implements Runnable
{
    private int i;
    public MyTask(int i)
    {
        this.i = i;
    }
    @Override
    public void run()
    {
        System.out.println("任务" + i + "开始执行" + System.currentTimeMillis());
        for (int i = 0; i < 32766; i++)
        {
            Random random = new Random();
            int randNum = random.nextInt();
            int[] a = {
                1
                , 2
                , 3
                , 4
                , 5
                , 6
                , 9
                , 18
                , 290
                , 238
                , 991
                , 100
                , 19
                , 1932
                , randNum
            };
            Arrays.sort(a);
            Arrays.hashCode(a);
            Arrays.stream(a);
        }
        System.out.println("任务" + i + "结束执行" + System.currentTimeMillis());
    }
}

我的电脑CPU核数为4,可以同时处理8线程,测试结果如下:

   核心池线程数量 执行耗时( 毫秒, 多次测试结果以 / 间隔)

  核心池线程数量 执行耗时( 毫秒, 多次测试结果以 / 间隔)
   4 474 / 479 / 471
   8 430 / 436 / 421
   12 432 / 425 / 438
   16 437 / 431 / 449
   20 471 / 481 / 469

我们看到,当线程数量小于CPU核数两倍时速度会明显下降,超过两倍后速度会相差不多,当核心池数量过多时,速度又会显著下降。

由此我们得出,核心池线程数量大小应在CPU核数两倍以上且不过多,这样是比较合适的。

以上就是本篇文章的所有内容了,线程池一直是java中的重要功能,想要了解更多线程池相关java常见问答知识,就请持续关注奇Q工具网吧。

推荐阅读:

创建线程池该如何创建?有几种方式?

线程池原理都有哪些?线程池是什么?

线程的生命周期包含几个阶段?