Java线程池

来源:互联网 发布:复旦大学大数据研究院 编辑:程序博客网 时间:2024/05/29 20:00

Java线程池

为了更好的控制多线程,JDK提供了一套Executor框架。在java.util.concurrent包中,是JDK并发包的核心类。其中ThreadPollExecutor表示一个线程池。Executors类扮演着线程池工厂的角色,它提供了一些具有特定功能的线程池。Executors通过工厂模式,可以获取下面几个线程池.

newCachedThreadPool()newCachedThreadPool(ThreadFactory threadFactory)newFixedThreadPool(int nThreads)newFixedThreadPool(int nThreads,ThreadFactory threadFactory)newScheduledThreadPool(int corePoolSize)newScheduledThreadPool(int corePoolSize,ThreadFactory threadFactory)newSingleThreadExecutor()newSingleThreadExecutor(ThreadFactory threadFactory)newSingleThreadScheduledExecutor()newSingleThreadScheduledExecutor(ThreadFactory threadFactory)

newFixedThreadPool(): 返回一个固定线程数量的线程池,该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲线程,则立即执行,否则新的任务会被暂存在一个任务队列中,待有线程空闲时,便处理任务队列中的任务。
newSingleThreadExecutor() 返回只有一个线程的线程池。若有多余一个任务被提交到该线程池,任务会被保存在一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务。
newCachedThreadPool() 返回一个可根据实际情况调整线程数量的线程池。线程池的线程数量不确定,但若有空闲线程可以复用,则会优先使用可复用的线程。若所有的线程均在工作,又有新的任务提交,则会创建新的线程处理任务。所有的线程在当前任务执行完毕后,将返回线程池进行复用。
newSingleThreadScheduledExecutor() 返回一个ScheduledExecutorService对象,线程池大小为1.ScheduledExecutorService接口在ExecutorService上进行了给定时间执行某任务的功能,如在某个固定的执行之后执行,或者周期性执行某个任务。


自定义线程池

ThreadPoolExecutor

以上参数大部分都比较简单,这里只对workQueuehandler进行说明。

参数workQueue指被提交但未执行的任务队列,它是一个BlockingQueue接口的对象,仅用于存放Runnable对象。根据队列功能分类,在ThreadPoolExecutor的构造函数中可使用以下几种BlockingQueue:
直接提交的队列:改功能由SynchronousQueue对象提供。SynchronousQueue是一个特殊的BlockingQueue。它没有容量,每一个插入操作都要等待一个相应的删除操作,反之,每一个删除操作都要等待一个相应的插入操作。SynchronousQueue不保存任务,它总是将任务提交给线程池执行,如果没有空闲线程,则尝试创建新的线程,如果线程数量已经达到最大值,则进行拒绝策略。因此SynchronousQueue队列,通常要设置很大的maximumPoolSize值,否则很容易执行异常策略。

有界的任务队列: 有界的任务队列可使用ArrayBlockingQueue实现。它的构造函数必须带一个容量参数,表示该队列的最大容量:public ArrayBlockingQueue(int capacity)
当使用有界的任务队列时,若有新的任务需要执行,如果线程池的实际线程数小于corePoolSize,则会优先创建新的线程,若大于corePoolSize,则会将新任务加入等待队列,若等待队列已满,无法加入,则在总线程数不大于maximumPoolSize的前提下,创建新的线程执行任务,若大于maximumPoolSize,则执行拒绝策略。可见,有界队列仅当任务队列装满时,才可能将线程数提升到corePoolSize以上,换言之,除非系统非常繁忙,否则确保核心线程维持在corePoolSize。

无界的任务队列:无界任务队列可以通过LinkedBlockingQueue类实现(例如Android-OkHttp,AsyncTask)。与有界队列相比,除非系统资源耗尽,否则无界任务队列不存在任务入队失败的情况。当有任务到来,系统线程小于corePoolSize时线程池会生成新的线程执行任务,但是当系统的线程达到corePoolSize后,就不会继续增加。若后续任由新的任务加入,而又没有空闲的线程资源,则任务直接进入队列等待。若任务创建和处理的速度差异很大,无界队列会保持快速增长,直到资源耗尽。
优先任务队列:优先任务队列时带有执行优先级的队列,它通过PriorityBlockingQueue实现。可以控制任务的执行先后顺序,是一个特殊的无界队列。无论是有界队列ArrayBlockingQueue,还是未制定大小的无界队列LinkedBlockingQueue都是按照先进先出算法处理任务的。而PriorityBlockingQueue则可以根据任务自身的优先级顺序先后执行,在确保系统性能的同时,也能有很好的质量保证(总能确保高优先级的任务先执行)。

了解了BlockingQueue,在回过头看newFixedThreadPool()方法的实现,可以发现它使用了corePoolSize和maximumPoolSize大小一样的,并且使用LinkedBlockingQueue任务队列的线程池。
newSingleThreadExecutor(),是newFixedThreadPool()的一种特殊特殊处理,只是将corePoolSize设置为1。
newCachedThreadPool()方法返回的corePoolSize为0,maximumPoolSize无穷大的线程池,这意味着没有任务时线程池中线程数为0,当有任务被提交时,会使用空闲线程,没有空闲线程,那么将任务添加到SynchronousQueue队列,而该队列时一种直接提交的队列,它会迫使线程池增加新的线程执行任务。任务执行完毕后,由于corePoolSize=0,空闲线程存活时间被指定为60s,如果短时间内有大量任务被提交,而每个任务又比较耗时,那么此时系统资源容易被耗尽。

参数handler指定拒绝策略,即当任务数量超过系统实际承受能力时,该如何处理,JDK提供了4中拒绝策略:

AbortPolicy策略:该策略会直接抛出异常,阻止系统正常工作。

CallerRunsPolicy策略:只要线程未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务

DiscardOledestPolicy策略:丢弃最老的一个请求,也就是即将被执行的一个任务,并尝试再次提交当前任务。

DiscardPolicy:该策略默默丢弃无法处理的任务,不予任何处理。

如果上面4种内置策略无法满足用户可以通过实现RejectedExecutionHandler接口。

原创粉丝点击