线程池的拒绝策略(重要)

排队策略

1.直接提交 SynchronousQueuejava

       它将任务直接提交给线程而不保存它们。在此,若是不存在可用于当即运行任务的线程,则试图把任务加入队列将失败,所以会构造一个新的线程。此策略能够避免在处理可能具备内部依赖性的请求集时出现锁。直接提交一般要求无界 maximumPoolSizes 以免拒绝新提交的任务。当命令以超过队列所能处理的平均数连续到达时,此策略容许无界线程具备增加的可能性。  SynchronousQueue线程安全的Queue,能够存放若干任务(但当前只容许有且只有一个任务在等待),其中每一个插入操做必须等待另外一个线程的对应移除操做,也就是说A任务进入队列,B任务必须等A任务被移除以后才能进入队列,不然执行异常策略。你来一个我扔一个,因此说SynchronousQueue没有任何内部容量。安全

       好比:核心线程数为2,最大线程数为3;使用SynchronousQueue。多线程

       当前有2个核心线程在运行,又来了个A任务,两个核心线程没有执行完当前任务,根据若是运行的线程等于或多于 corePoolSize,spa

      则 Executor 始终首选将请求加入队列,而不添加新的线程。因此A任务被添加到队列,此时的队列是SynchronousQueue,操作系统

      当前不存在可用于当即运行任务的线程,所以会构造一个新的线程,此时又来了个B任务,两个核心线程尚未执行完。.net

       新建立的线程正在执行A任务,因此B任务进入Queue后,最大线程数为3,发现没地方仍了。就只能执行异常策略(RejectedExecutionException)。线程

2 无界队列 如LinkedBlockingQueuecode

        使用无界队列(例如,不具备预约义容量的 LinkedBlockingQueue)将致使在全部核心线程都在忙时新任务在队列中等待。这样,建立的线程就不会超过 corePoolSize。(所以,maximumPoolSize 的值也就没意义了。)也就不会有新线程被建立,都在那等着排队呢。若是未指定容量,则它等于 Integer.MAX_VALUE。若是设置了Queue预约义容量,则当核心线程忙碌时,新任务会在队列中等待,直到超过预约义容量(新任务没地方放了),才会执行异常策略。你来一个我接一个,直到我容不下你了。FIFO,先进先出。blog

        好比:核心线程数为2,最大线程数为3;使用LinkedBlockingQueue(1),设置容量为1。队列

        当前有2个核心线程在运行,又来了个A任务,两个核心线程没有执行完当前任务,根据若是运行的线程等于或多于 corePoolSize,

        则 Executor 始终首选将请求加入队列,而不添加新的线程。因此A任务被添加到队列,此时的队列是LinkedBlockingQueue,

        此时又来了个B任务,两个核心线程没有执行完当前任务,A任务在队列中等待,队列已满。因此根据若是没法将请求加入队列,则建立新的线程,

         B任务被新建立的线程所执行,此时又来个C任务,此时maximumPoolSize已满,队列已满,只能执行异常策略(RejectedExecutionException)。

3.有界队列。

    当使用有限的 maximumPoolSizes 时,有界队列(如 ArrayBlockingQueue)有助于防止资源耗尽,可是可能较难调整和控制。队列大小和最大池大小可能须要相互折衷:使用大型队列和小型池能够最大限度地下降 CPU 使用率、操做系统资源和上下文切换开销,可是可能致使人工下降吞吐量。若是任务频繁阻塞(例如,若是它们是 I/O 边界),则系统可能为超过您许可的更多线程安排时间。使用小型队列一般要求较大的池大小,CPU 使用率较高,可是可能遇到不可接受的调度开销,这样也会下降吞吐量。

拒绝策略

1.AbortPolicy

为java线程池默认的阻塞策略,不执行此任务,并且直接抛出一个运行时异常,切记ThreadPoolExecutor.execute须要try catch,不然程序会直接退出。

2.DiscardPolicy

直接抛弃,任务不执行,空方法

3.DiscardOldestPolicy

从队列里面抛弃head的一个任务,并再次execute 此task。

4.CallerRunsPolicy

在调用execute的线程里面执行此command,会阻塞入口

 

参考博文:

ThreadPoolExecutor中策略的选择与工做队列的选择(java线程池)

相关文章
相关标签/搜索