面试必问系列 创建线程池有哪几种方式?

创建线程池有哪几种方式?

  • Executors.newFixedThreadPool(4);

    • 实际实现 new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())
    • 固定线程数为4 同时超出线程数将放在 LinkedBlockingQueue 中 默认是Integer.MAX_VALUE 可能阻塞过多可能出现 oom
  • Executors.newSingleThreadExecutor();

    • 实际实现 new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()))
    • 固定线程数为1 和newFixedThreadPool 区别包裹了 FinalizableDelegatedExecutorService 这样就无法转成ThreadPoolExecutor 也就不能修改线程数了
  • Executors.newScheduledThreadPool(4);

    • 实际实现 new ScheduledThreadPoolExecutor(corePoolSize);
    • 固定线程 返回可定时 可延时 处理的 ScheduledThreadPoolExecutor

    ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService

  • Executors.newCachedThreadPool();

    • 实际实现 new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
    • 固定线程数为0 可以无限增长Integer.MAX_VALUE 会有oom
  • Executors.newWorkStealingPool();

    • 实际实现 new ForkJoinPool (Runtime.getRuntime().availableProcessors(), ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true) java.util.concurrent.ForkJoinPool
    • 适用于耗时长的线程任务
  • 推荐使用 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)

    • 几个参数
      • 核心线程池数

        • 如果运行的线程少于 corePoolSize,则创建新线程来处理任务,即使线程池中的其他线程是空闲的;
        • 如果线程池中的线程数量大于等于 corePoolSize 且小于 maximumPoolSize,则只有当workQueue满时才创建新的线程去处理任务;
        • 如果设置的corePoolSize 和 maximumPoolSize相同,则创建的线程池的大小是固定的,这时如果有新任务提交,若workQueue未满,则将请求放入workQueue中,等待有空闲的线程去从workQueue中取任务并处理;
        • 如果运行的线程数量大于等于maximumPoolSize,这时如果workQueue已经满了,则通过handler所指定的策略来处理任务;
        • 所以,任务提交时,判断的顺序为 corePoolSize –> workQueue –> maximumPoolSize。
      • 最大线程数

      • 空任务回收时长

      • 空任务回收时长单位

      • 超出线程池的任务阻塞队列

        • 直接切换:这种方式常用的队列是SynchronousQueue
        • 使用无界队列:一般使用基于链表的阻塞队列LinkedBlockingQueue。如果使用这种方式,那么线程池中能够创建的最大线程数就是corePoolSize,而maximumPoolSize就不会起作用了(后面也会说到)。当线程池中所有的核心线程都是RUNNING状态时,这时一个新的任务提交就会放入等待队列中
        • 使用有界队列:一般使用ArrayBlockingQueue。使用该方式可以将线程池的最大线程数量限制为maximumPoolSize,这样能够降低资源的消耗,但同时这种方式也使得线程池对线程的调度变得更困难,因为线程池和队列的容量都是有限的值,所以要想使线程池处理任务的吞吐率达到一个相对合理的范围,又想使线程调度相对简单,并且还要尽可能的降低线程池对资源的消耗,就需要合理的设置这两个数量
      • 线程工厂

        • 常用 默认Executors.defaultThreadFactory() 这种会设定默认线程名 和 普通优先级 和 非守护线程
        • 推荐 重写成带线程池名工厂 方便定位问题
      • 超出策略

        • AbortPolicy:直接抛出异常,这是默认策略;
        • CallerRunsPolicy:用调用者所在的线程来执行任务;
        • DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务;
        • DiscardPolicy:直接丢弃任务;

线程池流程

线程池都有哪些状态?

源码中状态定义


    // runState is stored in the high-order bits
    private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;

状态变换

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木秀林

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值