Java线程池学习整理

134 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

一、使用线程池的好处:

  • 降低资源损耗。通过重复利用已创建的线程降低线程创建和销毁的损耗。
  • 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
  • 提高线程的可管理性。使用线程池可以进行统一的分配,调优和监控。

二、ThreadPoolExecutor中最重要的参数:

  • corePoolSize:核心线程数。最小可以同时运行的线程数。
  • maximumPoolSize:当队列中存放的任务达到队列容量的时候,当前可以同时运行的最大线程数。
  • workQueue:当新任务来的时候会先判断当前运行的线程数量是否达到corePoolSize,如果达到的话,新任务就会被存放在队列中。如果workQueue已经满了的话就执行拒绝策略。
  • keepAliveTime:当线程池中的线程数量大于 corePoolSize 的时候,核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了 keepAliveTime 才会被销毁。
  • unit : keepAliveTime 参数的时间单位。
  • threadFactory:executor 创建新线程的时候会用到。
  • handler:拒绝策略。

三、线程数配置公式:

  • CPU密集型任务(N+1):这种任务消耗的主要是CPU资源,可以将线程数设置为N(CPU核心数)+1,比CPU核心数多出来的一个线程是为了防止线程偶发的缺页中断,或者其它原因导致的任务暂停而带来的影响。一旦任务暂停,CPU就会处于空闲状态,而在这种情况下多出来的一个线程就可以充分利用CPU的空闲时间。
  • I/O密集型任务(2N):这种任务应用起来,系统会用大部分的时间来处理I/O交互,而线程在处理I/O的时间段内不会占用CPU来处理,这时就可以将CPU交出给其它线程使用。因此在I/O密集型任务的应用中,我们可以多配置一些线程,具体的计算方式是2N。

四、线程池的几种类型:

1.固定数量的线程池 newFixedThreadPool

作用:这是一个线程数固定的,线程可以重用的线程池,用共享的无界队列方式运行这些线程。 如果所有的核心线程都在忙,这时又有新的任务来,这个新的任务会去队列中等待。 如果一个线程在半路突然中止了,那么会有一个新的线程代替它执行后续的任务。 一个线程在被关闭之前,它会一直在线程池中等待被调用。

特征:

  1. 线程池中线程的量固定,可以控制线程的并发量。\
  2. 线程可以被重复利用\
  3. 任务数超出核心线程数时,那些额外的任务需要去队列中等待。如果队列中都挤满了,又有新的任务来,就会派额外的新线程去接客。如果达到了最大线程数后,还有新的任务来,那就直接抛异常吧,干不了了。

2.缓存线程池 newCachedThreadPool

作用:它是根据需要,创建线程,没有核心线程,当60s内这个线程没接收到任务时,它就会被从池中收走。60s内这个线程又接收到新任务时,它就又被重用了。

特征:

  1. 线程池中线程的数量不固定,最大值是Integer的最大值
  2. 池中的线程干完活后会等待1分钟(默认的),如果1分钟内又有新任务,这个线程就被调用去干新任务了,如果等了1分钟还没有新任务,这个线程就被从池中清理出去了。
  3. 当池中没有可用线程时,就创建一个新线程。

3.只有一个线程的线程池 newSingleThreadPool

作用:这个线程池中只有1个线程,用无界队列的方式运行。如果这个线程突然挂掉了,线程池会新建一个新的线程顶替它,继续完成任务。

特征:池中只有1个线程,任务要在队列中排队。当需要保证任务执行顺序时,适合用它。

4.延时线程池 newScheduleThreadPool

作用:创建一个线程池,可以让它里面的线程延迟执行,或在规定的时间后执行。

特征:

  1. 这个池中的线程,可以让它们延迟干活,或规定时间干活(不用来一个任务就去干)
  2. 线程池中的线程数量固定,即使没有任务,这些线程也保留。(没活也得待在公司)