线程池和进程池
池:在保证计算机硬件安全的情况下,最大限度的利用计算机资源,提前创建一定量的进程及线程,虽降低了程序的运行效率,但是保证了计算机的硬件安全
进程池:由服务器预先创建的一组子进程,子进程的数目在3~10个之间(httpd守护进程使用7个子进程的进程池实现并发的,一般地线程池的线程数目应该与CPU的数量差不多),进程池中的所有子进程都运行着相同的代码,并具有相同的属性,比如优先级、 PGID 等
线程池:java中经常需要用到多线程来处理一些业务,但是单纯使用继承Thread或者实现Runnable接口的方式来创建线程,势必有创建及销毁线程耗费资源、线程上下文切换问题。同时创建过多的线程也可能引发资源耗尽的风险,所以引入线程池,方便线程任务的管理
进程池
1、引入原因:
① 动态创建进程(或线程)比较耗费时间,这将导致较慢的客户响应
② 动态创建的子进程通常只用来为一个客户服务,这样导致了系统上产生大量的细微进程(或线程)。进程和线程间的切换将消耗大量CPU时间
③ 动态创建的子进程是当前进程的完整映像,当前进程必须谨慎的管理其分配的文件描述符和堆内存等系统资源,否则子进程可能复制这些资源,从而使系统的可用资源急剧下降,进而影响服务器的性能。
④池子使用来限制并发的任务数目,限制我们的计算机在一个自己可承受的范围内去并发地执行任务
2、子进程选择方法有二:
① 主进程使用某种算法来主动选择子进程。最简单、最常用的算法是随机算法和 Round Robin (轮流算法)
② 主进程和所有子进程通过一个共享的工作队列来同步,子进程都睡眠在该工作队列上。当有新的任务到来时,主进程将任务添加到工作队列中。这将唤醒正在等待任务的子进程,不过只有一个子进程将获得新任务的“接管权”,它可以从工作队列中取出任务并执行之,而其他子进程将继续睡眠在工作队列上
线程池
为什么创建线程池
创建线程要花费昂贵的资源和时间,如果任务来了才创建线程那么响应时间会变长,而且一个进程能创建的线程数有限。为了避免这些问题,在初始化一个多线程应用程序过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是新建一个线程,它们被称为线程池,里面的线程叫工作线程
线程池的实现原理
线程池是通过在一个线程安全的阻塞任务队列加上一个或多个的线程实现,线程池中的线程可以从阻塞任务队列中获取任务然后进行任务处理
① 线程池会判断核心线程池(corePoll)中的线程是否都在执行中,如果不是(核心线程池并不是线程池的所有线程),则创建一个新的线程来执行任务,否则进入下一个流程(需要获取全局锁)
② 线程池会判断工作队列(堵塞队列 BlockingQueue)是否已满,如果堵塞队列未满,则该任务加入到这个堵塞队列中,如果满了,则进入下一个流程
③ 线程池判断线程池中的所有线程(maximumPool)是否都处于工作状态,如果没有(所有线程,少于线程池的最大线程数),则创建一个新的工作线程来完成任务(此操作也需要获取全局锁),如果所有线程都处于工作状态,则交给饱和策略来处理这个任务,默认是抛出异常
注:线程池的设计其实主要是在执行execute方法的时候,尽可能的去避免获取全局锁(因为那是一个很严重的可伸缩瓶颈)。在线程池完成预热后,当前运行的线程是大于核心线程池的,所以几乎所有的execute方法都会把该任务加入到阻塞队列中去,从而避免获取全局锁
工作线程
线程池在创建线程的时候会把线程封装成工作线程Worker,Worker在执行完任务之后,还会循环获取工作队列中的任务来执行
线程池优点
① 线程池改进了一个应用程序的响应时间。
② 线程池节省了CLR为每个短生存周期任务创建一个完整的线程的开销并可以在任务完成后回收资源。
③ 线程池根据当前在系统中运行的进程来优化线程时间片。
④ 线程池允许我们开启多个任务而不用为每个线程设置属性。
⑤ 线程池可以用来解决处理一个特定请求最大线程数量限制问题