线程池工作队列饱和策略

原创 2016年07月03日 00:13:03

近段时间在看《Java并发编程实战》,第一遍每天看一章也没敲代码,并没吸收多少。看第二遍的时候压下速度,并敲代码,感觉理解深刻好多,废话止于此。


Java线程池会将提交的任务先置于工作队列中,在从工作队列中获取(SynchronousQueue直接由生产者提交给工作线程)。那么工作队列就有两种实现策略:无界队列和有界队列。无界队列不存在饱和的问题,但是其问题是当请求持续高负载的话,任务会无脑的加入工作队列,那么很可能导致内存等资源溢出或者耗尽。而有界队列不会带来高负载导致的内存耗尽的问题,但是有引发工作队列已满情况下,新提交的任务如何管理的难题,这就是线程池工作队列饱和策略要解决的问题。

饱和策略分为:Abort 策略, CallerRuns 策略,Discard策略,DiscardOlds策略。

为了更好的理解,我编写一个小的例子。

package concurrency.pool;

import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Created by li on 2016/7/2.
 */
public class SaturationPolicy {

    /**
     * 线程池工作队列已满时,在不同饱和策略下表现
     * @param handler 线程池工作队列饱和策略
     */
    public static void policy(RejectedExecutionHandler handler){
        //基本线程2个,最大线程数为3,工作队列容量为5
        ThreadPoolExecutor exec = new ThreadPoolExecutor(2,3,0l, TimeUnit.MILLISECONDS,new LinkedBlockingDeque<>(5));
        if (handler != null){
            exec.setRejectedExecutionHandler(handler);//设置饱和策略
        }
        for (int i = 0; i < 10; i++) {
            exec.submit(new Task());//提交任务
        }
        exec.shutdown();
    }

    public static void main(String[] args) {
//        policy(new ThreadPoolExecutor.AbortPolicy());
//        policy((new ThreadPoolExecutor.CallerRunsPolicy()));
//        policy(new ThreadPoolExecutor.DiscardPolicy());
//        policy(new ThreadPoolExecutor.DiscardOldestPolicy());
    }

    //自定义任务
    static class Task implements Runnable {
        private static int count = 0;
        private int id = 0;//任务标识
        public Task() {
            id = ++count;
        }
        @Override
        public  void run() {
            try {
                TimeUnit.SECONDS.sleep(3);//休眠3秒
            } catch (InterruptedException e) {
                System.err.println("线程被中断" + e.getMessage());
            }
            System.out.println(" 任务:" + id + "\t 工作线程: "+ Thread.currentThread().getName() + " 执行完毕");
        }
    }

}

当工作队列满了,不同策略的处理方式为:

1.Abort策略:默认策略,新任务提交时直接抛出未检查的异常RejectedExecutionException,该异常可由调用者捕获。

 在主函数中添加如下代码:

policy(new ThreadPoolExecutor.AbortPolicy());
运行结果为:


程序抛出了RejectedExecutionException,并且一共运行了8个任务(线程池开始能运行3个任务,工作队列中存储5个队列)。当工作队列满了的时候,直接抛出了异常,而且JVM一直不退出(我现在也不知道什么原因)。我们可以看到执行任务的线程全是线程池中的线程。

2.CallerRuns策略:为调节机制,既不抛弃任务也不抛出异常,而是将某些任务回退到调用者。不会在线程池的线程中执行新的任务,而是在调用exector的线程中运行新的任务。

在主函数运行:

 policy((new ThreadPoolExecutor.CallerRunsPolicy()));
运行结果


所有的任务都被运行,且有2(10 - 3 -5)个任务是在main线程中执行成功的,8个任务在线程池中的线程执行的。
3.Discard策略:新提交的任务被抛弃。

在main函数中运行

policy(new ThreadPoolExecutor.DiscardPolicy());


通过上面的结果可以显示:没有异常抛出,后面提交的2个新任务被抛弃,只处理了前8(3+5)个任务,JVM退出。

4.DiscardOldest策略:队列的是“队头”的任务,然后尝试提交新的任务。(不适合工作队列为优先队列场景)

在main函数中运行如下方法

policy(new ThreadPoolExecutor.DiscardOldestPolicy());

运行结果:一共运行8个任务,程序结束,后面添加的任务9,任务10被执行了,而前面的任务3,任务4被丢弃。



版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lixwjava/article/details/51813032

Java并发编程(你不知道的线程池操作)

这几篇博客,一直在谈线程,设想一下这个场景,如果并发的线程很多,然而每个线程如果执行的时间很多的话,这样的话,就会大量的降低系统的效率。这时候就可以采用线程池的操作,来缓存我们并发操作的线程。    ...
  • ZHOUCHAOQIANG
  • ZHOUCHAOQIANG
  • 2015-09-04 09:40:01
  • 4368

线程池满了如何处理及spring参数设置:

线程池满了如何处理及spring参数设置:     多线程的问题,不仅仅考虑在代码中用线程池,在spring等上也许配置 并发问题也不是,单纯的在代码中同步,数据库zk等,也不仅仅是在ngin...
  • y666666y
  • y666666y
  • 2017-04-17 16:10:51
  • 1722

Java多线程:线程池简介及线程池之坑

线程池简介自JDK1.5,Java吊炸天的并发包就提供线程池java.util.concurrent.ThreadPoolExecutor ,先来看看其各个字段的含义: corePoolSize 核...
  • feichenwangyalin
  • feichenwangyalin
  • 2016-04-19 20:48:23
  • 3700

线程池和阻塞队列

从Java5开始,Java提供了自己的线程池。每次只执行指定数量的线程,java.util.concurrent.ThreadPoolExecutor 就是这样的线程池。以下是我的学习过程。 首...
  • cheng911215
  • cheng911215
  • 2014-08-20 16:16:25
  • 5918

线程池队列饱和策略

1、当一个有限队列充满后,线程池的饱和策略开始起作用。2、ThreadPoolExecutor的饱和策略通过调用setRejectedExecutionHandler来修改。不同的饱和策略如下:1)A...
  • okman1214
  • okman1214
  • 2009-10-26 12:49:00
  • 1228

线程池的饱和策略-调用者执行

使用java的任务管理框架的线程池执行任务时,线程池的任务等待队列被填满时,饱和策略开始发挥作用。ThreadPollExecutor的饱和策略通过setRejectedExecutionHandle...
  • wojiushiwo945you
  • wojiushiwo945you
  • 2014-12-15 15:36:21
  • 1670

java线程池与五种常用线程池策略使用与解析

java线程池与四种常用线程池策略使用与解析 一.线程池 关于为什么要使用线程池久不赘述了,首先看一下java中作为线程池Executor底层实现类的ThredPoolExecutor的构造函数 ...
  • u011479540
  • u011479540
  • 2016-07-09 18:23:46
  • 8256

Java线程池饱和策略

最近在看 Java并发编程的艺术一书,第9章提到了线程池的实现原理,其中有这么一句话: 线程池判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和...
  • u013249965
  • u013249965
  • 2017-03-01 16:14:24
  • 458

线程池之饱和策略

package com.ilucky.test.jdk.util.concurrent2;import java.util.ArrayList; import java.util.List; impo...
  • sidongxue2
  • sidongxue2
  • 2017-09-20 19:11:33
  • 190

线程池与线程队列分析-优

·  线程池是对象池的一个有用的例子,它能够节省在创建它们时候的资源开销。并且线程池对系统中的线程数量也起到了很好的限制作用。 ·  线程池中的线程数量必须仔细的设置,否则冒然增加线程数量只会带来性...
  • mawming
  • mawming
  • 2016-08-24 14:00:36
  • 4592
收藏助手
不良信息举报
您举报文章:线程池工作队列饱和策略
举报原因:
原因补充:

(最多只允许输入30个字)