课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
线程问题是程序员在学习软件编程开发技术的时候都被要求熟练掌握的编程技术知识之一,下面我们就通过案例分析来了解一下,线程池的执行与常见类型。
1、线程工厂
线程池的创建方法使用线程池的工厂类Executors,调用相应的方法创建相应的线程池。创建线程池的工作即实例化ThreadPoolExecutor,所以有必要简单看下ThreadPoolExecutor。
corePoolSize:线程池中的核心线程数。也就是线程池会长期保持的线程数。当通过线程池执行任务时,如果当前的线程数小于corePoolSize,则创建新线程,如果当前线程数已经为corePoolSize,则任务进入工作队列。如果希望一次性创建出核心线程,调用prestartAllCoreThreads()。
maximumPoolSize:池中允许的大线程数。当核心线程数满,并且阻塞队列也满了,此时如果池中的线程数仍小于maximumPoolSize,则会创建新的线程。
keepAliveTime:空闲线程存活的时间。仅当池中线程数大于corePoolSize时有效,也就是在上述maximumPoolSize所讲条件触发创建线程后,使得池中线程大于核心线程数后,才会根据该条件来销毁线程。
unit:时间单位。
workQueue:保存尚未执行的任务的阻塞队列。
threadFactory:创建线程的工厂。
handler:饱和策略。也就是阻塞队列满了之后的处理方式。饱和策略有四种,AbortPolicy(抛出异常),CallerRunsPolicy(由调用线程直接执行,如果调用线程已经销毁则丢弃),DiscardOldestPolicy(丢弃早的任务,即队列头部的任务),DiscardPolicy(直接丢弃)。
2、任务的执行
用线程池执行任务有两种方式,execute和submit,execute无返回值,submit返回Future,而Future可以返回结果和接收异常。根据需要使用具体的方法。
3、线程池的停止
关闭线程池使用shutdown()和shutdownNow()。使用shutdown()时,尚未被执行的任务将不再执行,而已经在执行的任务将继续。使用shutdownNow()时,尚未被执行的任务将不再执行,并且会尝试停止正在运行的任务。
接下来简单介绍下几个常见线程池。
FixedThreadPool:
corePoolSize等于maximumPoolSize,阻塞队列使用了LinkedBlockingQueue,但并未初始化其容量,可以认为相当于使用了无界队列(为什么说到无界,文章后会提到)。适用于对服务器负载有严格控制的场景。
SingleThreadExecutor:
corePoolSize等于maximumPoolSize等于1,阻塞队列同样使用了未初始化容量的LinkedBlockingQueue,为无界队列。适用于对任务执行顺序有要求的场景。
CachedThreadPool:
corePoolSize为0,maximumPoolSize为Integer.MAX_VALUE,使用的队列为SynchronousQueue,同样为无界。该线程池会根据需要创建新线程,适用于执行时间非常短的数量较多的异步任务。
ScheduledThreadPool:
其maximumPoolSize为Integer.MAX_VALUE,队列使用了DelayedWorkQueue,同样为无界。适用于需要定期执行任务的场景。
SingleThreadScheduledExecutor
corePoolSize为1,队列同样使用了DelayedWorkQueue,为无界。适用于需要定期按顺序执行任务的场景。
WorkStealingPool:
工作密取队列,内部使用了ForkJoinPool,但使用了默认工厂创建,同样为无界形式。
4、自定义线程池
后说一下之前提到的无界问题。无界意味着如果出现处理不够及时的情况时,任务会逐渐堆积,而造成服务不可用或服务崩溃。所以在实际使用中通常需要自定义ThreadPoolExecutor,并在内部使用有界队列的方式或通过其他手段达到类似有界的效果。对于队列满时的饱和策略除了文中介绍的四种实现,同样可以根据实际情况自定义。
【免责声明】本文系本网编辑部分转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请在30日内与管理员联系,我们会予以更改或删除相关文章,以保证您的权益!更多内容请在707945861群中学习了解。