Java线程池参数、执行流程及线程数配置建议

422 阅读2分钟

1. 线程池参数详解

  • corePoolSize:线程池中常驻核心线程数;
  • maximumPoolSize:线程池能够容纳同时执行的最大线程数;
  • keepAliveTime:多余的空闲线程存活时间;
  • unit:keepAliveTime的时间单位;
  • workQueue:任务队列,被提交但尚未执行的任务;
  • threadFactory:表示生成线程池中的工作线程的线程工厂;可以用来设定线程名、是否为daemon线程等等;
  • handler:拒绝策略。

1.1. workQueue类型

  • ArrayBlockingQueue:基于数组的有界阻塞队列,先进先出;
  • LinkedBlockingQuene:基于链表的无界阻塞队列,先进先出;
  • SynchronousQuene:一个不缓存任务的阻塞队列,没有可用线程时会直接执行拒绝策略;
  • PriorityBlockingQueue:具有优先级的无界阻塞队列,优先级通过参数Comparator实现(二叉堆)。

1.2. handler类型

  • CallerRunsPolicy:在调用者线程中执行run方法;
  • AbortPolicy:丢弃任务,并抛出RejectedExecutionException异常;
  • DiscardPolicy:丢弃任务;
  • DiscardOldestPolicy:丢弃最早进入队列的任务,然后尝试将此任务加入队列。

2. 执行流程

image.png 注意: 线程池中的线程并未标记哪些是核心线程,哪些是临时线程。当线程池中的工作线程数超过核心线程数时,利用队列的poll(long timeout, TimeUnit unit)方法获取线程任务,当超过设置的存活时间未获取到任务时,线程运行结束等待JVM自然回收,由此可见创建的“临时线程”会一直执行任务直至队列为空;当线程池中的工作线程数不超过核心线程数时,调用的是take()方法让线程一直处于阻塞状态而不被回收,从而保证线程池的线程数维持在核心线程数以内。

3. 线程数配置建议

3.1. 任务类型

任务分为I/O密集型任务和CPU密集型任务。

  • I/O密集型:包括磁盘I/O,网络I/O。指的是任务中I/O操作占据主要时间,此时往往对CPU的使用率不高;
  • CPU密集型:又叫计算密集型。指的是任务中计算逻辑占据主要时间,此时往往对CPU会有比较高的使用率。

3.2. 配置建议

我们在程序中使用多线程的主要目的就是充分调动计算机资源用于提升程序性能。线程数设置的过少则计算机资源利用不充分,设置的过多则会造成大量线程切换反而影响程序性能,所以合理的配置线程数尤为重要。

  • I/O密集型:最佳线程数 = (1/CPU利用率) = 1 + (I/O耗时/CPU耗时);一般为2*CPU核心数;
  • CPU密集型:最佳线程数 = CPU核心数+1;+1是为了预防有个线程被阻塞,CPU可以调用其他线程。