线程池工作队列饱和策略

原创 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
  • 1506

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

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

线程池的四个中断策略

中断策略实际上是指饱和策略(concurent包中的RejectedExecutionHandler接口),这里需要先解释一下,什么叫饱和策略, 实际就是说, 线程池中的线程容器已经放不下新的任务了,...
  • xuanjiewu
  • xuanjiewu
  • 2016年01月27日 21:48
  • 1345

Java线程池(ThreadPoolExecutor)原理分析与使用

在我们的开发中“池”的概念并不罕见,有数据库连接池、线程池、对象池、常量池等等。下面我们主要针对线程池来一步一步揭开线程池的面纱。使用线程池的好处1、降低资源消耗 可以重复利用已创建的线程降低线程创...
  • fuyuwei2015
  • fuyuwei2015
  • 2017年05月25日 21:52
  • 2171

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

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

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

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

Java并发编程(八)《线程池》

Java并发编程八线程池 1 为什么使用线程池 2 线程池是什么结构怎样的怎么工作 21 线程池模型 22 线程池工作原理 23 ThreadPoolExecutor源码分析 231 数据结构 232...
  • lvmama_tujp
  • lvmama_tujp
  • 2017年07月10日 00:20
  • 207

Java多线程引发的性能问题以及调优策略

本文主要介绍了Java多线程引发的性能问题以及调优策略,包括对线程同步、线程池、以及伪共享所引发的问题,并提出了相应的解决方法......
  • luofenghan
  • luofenghan
  • 2017年11月21日 21:06
  • 726

JAVA线程池ThreadPoolExecutor与阻塞队列BlockingQueue

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

Java四种线程池和工作队列

public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { ...
  • u010002184
  • u010002184
  • 2017年12月02日 19:31
  • 76
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:线程池工作队列饱和策略
举报原因:
原因补充:

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