线程池提供了一种限制和管理资源(包括执行一个任务)。每个线程池还维护一些基本统计信息,例如已完成任务的数量。这里借用《Java并发编程的艺术》提到的来说一下使用线程池的好处:
  • 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  • 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
  • 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

请speak人话!

OK我们讲讲通俗易懂的:

诸如Web服务器、数据库服务器、文件服务器或邮件服务器之类的许多服务器应用程序都面向处理来自某些远程来源大量而短小的任务。服务器应用程序中经常出现的情况是:单个任务处理的时间很短但请求的数目却是巨大的。

而我们知道构建服务器程序的一个简单模型是:每当一个请求到达就创建一个新线程,然后在新线程中为请求服务。

这样我们就会想到,在很多时候线程的创建和销毁所花费的时间以及消耗系统资源要远比花在处理实际的用户请求的时间和资源更多。除此之外,活动的线程也消耗系统资源。在一个 JVM 里创建太多的线程可能会导致系统由于过度消耗内存而用完内存或“切换过度”。为了防止资源不足,服务器应用程序需要一些办法来限制任何给定时刻处理的请求数目。

这个时候线程池来啦!!它会为你创建很多的线程,放在它的小池子里,当请求到达了,就从中直接取用,用完以后再放回(线程回到空闲状态,等待下一次某个线程的取用)

我们就明白了它省去了线程的创建和销毁的时间,并且一个线程是可以重复使用的,大大节约了资源消耗,同时也提高了程序执行的效率。


 

现在我们一起看看如何创建一个线程池

Java中已经提供了创建线程池的一个类:Executor而我们创建时,一般使用它的子类:ThreadPoolExecutor

  •  
public ThreadPoolExecutor(int corePoolSize,                                int maximumPoolSize,                                long keepAliveTime,                                TimeUnit unit,                                BlockingQueue<Runnable> workQueue,                                ThreadFactory threadFactory,                                RejectedExecutionHandler handler)

 

 

这是其中最重要的一个构造方法,这个方法决定了创建出来的线程池的各种属性:

为什么要用线程池?_线程池

我们可以看出,线程池中的corePoolSize就是线程池中的核心线程数量,这几个核心线程,只是在没有用的时候,也不会被回收,maximumPoolSize就是线程池中可以容纳的最大线程的数量,而keepAliveTime,就是线程池中除了核心线程之外的其他的最长可以保留的时间,因为在线程池中,除了核心线程即使在无任务的情况下也不能被清除,其余的都是有存活时间的,而util,就是计算这个时间的一个单位,workQueue,就是等待队列,任务可以储存在任务队列中等待被执行,执行的是FIFIO原则(先进先出)。threadFactory,就是创建线程的线程工厂,最后一个handler,是一种拒绝策略,我们可以在任务满了之后,拒绝执行某些任务。

线程池的执行流程又是怎样的呢?
这个图一看就明了:

为什么要用线程池?_线程池_02

有图我们可以看出,任务进来时,首先执行判断,判断核心线程是否处于空闲状态,如果不是,核心线程就先就执行任务,如果核心线程已满,则判断任务队列是否有地方存放该任务,若果有,就将任务保存在任务队列中,等待执行,如果满了,在判断最大可容纳的线程数,如果没有超出这个数量,就开创非核心线程执行任务,如果超出了,就调用handler实现拒绝策略。
  •  
handler的拒绝策略:
有四种:第一种AbortPolicy:不执行新任务,直接抛出异常,提示线程池已满
       第二种DisCardPolicy:不执行新任务,也不抛出异常
       第三种DisCardOldSetPolicy:将消息队列中的第一个任务替换为当前新进来的任务执行
       第四种CallerRunsPolicy:直接调用execute来执行当前任务

四种常见的线程池
CachedThreadPool:可缓存的线程池,该线程池中没有核心线程,非核心线程的数量为Integer.max_value,就是无限大,当有需要时创建线程来执行任务,没有需要时回收线程,适用于耗时少,任务量大的情况。
SecudleThreadPool:周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大。适用于执行周期性的任务。
SingleThreadPool:只有一条线程来执行任务,适用于有顺序的任务的应用场景。
FixedThreadPool:定长的线程池,有核心线程,核心线程的即为最大的线程数量,没有非核心线程。

和松鼠一起学习:

为什么要用线程池?_线程池_03