JAVA面试官:线程池核心线程数,最大线程数怎么设置,有什么理论依据?你可不能回答CPU密集型设置CPU核心数 + 1;IO密集型CPU核心线程数 * 2!

起因        

        最近针对线程池的核心线程数设置多少与同事发生了一些歧义:

                我的理论依据是大厂面试中面试题和标准答案(曾经被虐过!):CPU密集型设置CPU核心数 + 1;IO密集型CPU核心数 * 2(可以远大于核心数)。
                其他人说实际开发中并没有人会在意这些设置多少无所谓,我觉得这实在是无法接受。

        于是我做了一波测试分别针对CPU密集型和IO密集型来看核心线程数和最大线程数对执行时间的影响。

最终结论

        但很多面试题中说的:“CPU密集型核心线程数过大超过CPU核心数那么执行时间反而会更久”。其实是不对的,应该是CPU密集型核心线程数过大超过CPU核心数那么执行时间可能会出现波动较大的情况不稳定,原因可能是:
        GC / JIT / cache / context switch。

过程结论

CPU密集型任务结论是:
        - 线程上下文切换造成的开销其实并没有想象中那么大。
        - CPU密集型耗费时间情况:

线程数 < 核心数:执行速度 吞吐能力线性上升

线程数 ≈ 核心数:执行速度 达到峰值(最快)

线程数 > 核心数:

        出现上下文切换 + cache miss + 调度竞争
        执行速度 吞吐能力进入瓶颈不会有显著提升

        出现吞吐能力的抖动(不稳定可能会出现大于1.5倍~2倍的平均执行速度)

        猜测不稳定因素:GC / JIT / cache / context switch


实验参数:
    - 核心线程数和最大线程数都是从1~300变化,不同的线程数执行10次子线程任务。
    - 每个子线程执行200_000_000L次Math.sqrt(i)。

IO密集型任务结论是:


 

  - 线程上下文切换造成的开销其实并没有想象中那么大。
  - 线程越大→ 性能快速提升 → 达到平台期 → 不再变化。


实验参数:
    - 核心线程数和最大线程数都是从1~300变化,不同的线程数执行10次子线程任务。
    - 每个子线程执行

        Thread.sleep(200)

代码:

package com.luology.test.test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Test {

    public static void main(String[] args) throws Exception {

        int cpu = Runtime.getRuntime().availableProcessors();

        System.out.println("CPU核心数:" + cpu);

        for (int threadNum = 1; threadNum <= 300; threadNum++) {

            test(threadNum);
        }
    }

    private static void test(int threadNum)
            throws Exception {

        ExecutorService pool = Executors.newFixedThreadPool(threadNum);

        long start = System.currentTimeMillis();

        List<Future<Long>> futures = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            futures.add(pool.submit(
                    new CpuTask(100000)
            ));
        }

        for (Future<Long> future : futures) {
            future.get();
        }

        long end = System.currentTimeMillis();

        pool.shutdown();

        System.out.printf(
                "线程数=%d,耗时=%dms%n",
                threadNum,
                end - start
        );
    }
}
package com.luology.test.test;

import java.util.concurrent.Callable;

public class CpuTask implements Callable<Long> {

    private final int num;

    public CpuTask(int num) {
        this.num = num;
    }

    @Override
    public Long call() throws InterruptedException {
        // ### CPU密集型任务
//        double sum = 0;
//
//        for (long i = 0; i < 200_000_000L; i++) {
//            sum += Math.sqrt(i);
//        }
//
//        return (long) sum;

        // ### IO 密集型任务
        Thread.sleep(200);

        return 1L;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值