线程池工作队列饱和策略

原创 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被丢弃。



版权声明:本文为博主原创文章,未经博主允许不得转载。

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

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

Java 理论和实践:线程池和工作队列

使用线程池以获取最佳资源利用率Java 多线程编程论坛中最常见的一个问题就是各种版本的 "我怎么样才可以创建一个线程池?" 几乎在每个服务器应用里,都会出现关于线程池和工作队列的问题。本文中,Bria...
  • defonds
  • defonds
  • 2015年02月13日 19:08
  • 3528

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

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

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

工作原理 1、线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。 2、当调用 execute() 方法添加一个任务时,线程池...
  • keda8997110
  • keda8997110
  • 2014年07月07日 14:42
  • 1835

JAVA线程池ThreadPoolExecutor与阻塞队列BlockingQueue

从Java5开始,Java提供了自己的线程池。每次只执行指定数量的线程,java.util.concurrent.ThreadPoolExecutor 就是这样的线程池。以下是我的学习过程。 首...
  • zhangweikai966
  • zhangweikai966
  • 2016年08月22日 14:50
  • 3575

Java四种线程池和工作队列

public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { ...
  • u010002184
  • u010002184
  • 2017年12月02日 19:31
  • 72

JAVA线程池学习以及队列拒绝策略

有关线程池接受任务的执行顺序
  • xjwxz
  • xjwxz
  • 2016年06月29日 13:38
  • 2741

JAVA线程池ThreadPoolExecutor与阻塞队列BlockingQueue

从Java5开始,Java提供了自己的线程池。每次只执行指定数量的线程,java.util.concurrent.ThreadPoolExecutor 就是这样的线程池。以下是我的学习过程。 首先是...
  • shixing_11
  • shixing_11
  • 2011年12月28日 17:48
  • 32156

javaWeb 使用线程池+队列解决"订单并发"问题

遇到问题: 最近做微信支付,项目上线一阵,发现一个问题。有一条订单流水居然在数据库的出现两次。这个问题非常严重。 查看微信回调系统的接口代码发现代码是没错的(正常情况下),而这次遇到非正常情况了 ...
  • white__cat
  • white__cat
  • 2017年02月24日 09:06
  • 4608

多线程的一些问题

原文地址:http://www.cnblogs.com/xrq730/p/5060921.html 前言 多线程分类中写了21篇多线程的文章,21篇文章的内容很多,个人认为,学习,内容...
  • kongxiuqi
  • kongxiuqi
  • 2016年11月11日 15:22
  • 614
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:线程池工作队列饱和策略
举报原因:
原因补充:

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