最近项目中要用到多线程处理任务,自然就用到了ThreadPoolTaskExecutor这个对象,这个是spring对于Java的concurrent包下的ThreadPoolExecutor类的封装,对于超出等待队列大小的任务默认是使用RejectedExecutionHandler去处理拒绝的任务,而这个Handler的默认策略是AbortPolicy,直接抛出RejectedExecutionException异常,这个不符合我们的业务场景,

业务需求:我希望是对于超出的任务,主线程进行阻塞,直到有可用线程,简单的代码如下

package com.quant.dev.modules.dev.enetity;

import lombok.extern.slf4j.Slf4j;

import java.net.URL;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock; /**
* @program: dev
* @description:
* @author: Mr.EternityZhang
* @create: 2019-07-08 17:41
*/
@Slf4j
public class TestThread { static class ThreadFactoryCustom implements ThreadFactory{
private final AtomicInteger threadNum=new AtomicInteger(1);
private final String namePrefix; private ThreadFactoryCustom(String namePrefix){
this.namePrefix=namePrefix+"-";
} @Override
public Thread newThread(Runnable r) {
Thread t=new Thread(r,namePrefix+threadNum.getAndIncrement());
if(t.isDaemon()){
t.setDaemon(true);
}
if(t.getPriority()!=Thread.NORM_PRIORITY){
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
}
} static class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy { private final String threadName; private final URL url; public AbortPolicyWithReport(String threadName, URL url) {
this.threadName = threadName;
this.url = url;
} @Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
String msg = String.format("Provider端线程池满!" +
" Thread Name: %s, Pool Size: %d (active: %d, core: %d, max: %d, largest: %d), Task: %d (completed: %d)," +
" Executor status:(isShutdown:%s, isTerminated:%s, isTerminating:%s)" ,
threadName, e.getPoolSize(), e.getActiveCount(), e.getCorePoolSize(), e.getMaximumPoolSize(), e.getLargestPoolSize(),
e.getTaskCount(), e.getCompletedTaskCount(), e.isShutdown(), e.isTerminated(), e.isTerminating());
log.warn(msg);
if (!e.isShutdown()) {
try {
log.info("start get queue");
e.getQueue().put(r);
log.info("end get queue");
} catch (InterruptedException ee) {
log.error(ee.toString(), ee);
Thread.currentThread().interrupt();
}
}
} } public static ThreadFactory getThreadFactoryCustom(String name){
return new ThreadFactoryCustom(name);
} public static void main(String[] args) {
String poolName="eternity";
ThreadFactory factory=getThreadFactoryCustom(poolName);
log.info("核数={}",Runtime.getRuntime().availableProcessors());
ThreadPoolExecutor executor=
new ThreadPoolExecutor(100,400,5,
TimeUnit.SECONDS,new LinkedBlockingDeque<>(400),factory,new AbortPolicyWithReport(poolName,null));
Long begin=System.currentTimeMillis();
CountDownLatch count=new CountDownLatch(2000);
AtomicInteger integer=new AtomicInteger(1);
for(int i=0;i<2000;i++){
executor.execute(()->{
try {
log.info("当前线程为={},数值={}",Thread.currentThread().getName(),integer);
integer.getAndIncrement();
Thread.sleep(500);
count.countDown();
} catch (Exception e) {
e.printStackTrace();
}
});
}
try {
count.await();
log.info("阻塞数值={}",count.getCount());
log.info("活跃数量={}",executor.getActiveCount());
if(executor.getActiveCount()==0){
executor.shutdown();
}
} catch (Exception e) {
e.printStackTrace();
}
log.info("耗时={}------结果={}",System.currentTimeMillis()-begin,integer);
}
}

阻塞原理:

之所以能实现阻塞,是基于BlockingQueue的put方法来实现的,当阻塞队列满时,put方法会一直等待

参考

https://www.jianshu.com/p/3cfd943996a1

重写ThreadFactory方法和拒绝策略的更多相关文章

  1. JUC之线程池-三大方法-七大参数-四种拒绝策略

    线程池:重点 三大方法 七大参数 四种拒绝策略 使用池化技术的理由: 我们的程序伴随着创建销毁线程十分浪费资源, 所以使用线程池,先创建线程,随用随取,用完归还 简单来说就是节约了资源. 使用线程池的 ...

  2. juc线程池原理(三):ThreadFactory、拒绝策略、提交任务、关闭线程池

    概要 (一) ThreadFactory 线程池中的ThreadFactory是一个线程工厂,线程池创建线程都是通过线程工厂对象(threadFactory)来完成的. 类图如下: 上面所说的thre ...

  3. SimpleThreadPool给线程池增加拒绝策略和停止方法

    给线程池增加拒绝策略和停止方法 package com.dwz.concurrency.chapter13; import java.util.ArrayList; import java.util. ...

  4. JUC 并发编程--08,线程池,三大方法,七大参数,4种拒绝策略,代码演示

    三大方法: //线程池核心线程数为n, 最大线程数为 n ExecutorService fixedThreadPool = Executors.newFixedThreadPool(n); 源码: ...

  5. JDK线程池的拒绝策略

    关于新疆服务请求未带入来话原因的问题 经核查,该问题是由于立单接口内部没有成功调用接续的 “更新来电原因接口”导致的,接续测更新来电原因接口编码:NGCCT_UPDATESRFLAG_PUT ,立单接 ...

  6. @EnableAsync @Asnc 以及4种拒绝策略

    根据不同的场景,可以选择不同的拒绝策略,如果任务非常重要,线程池队列满了,可以交由调用者线程同步处理. 如果是一些不太重要日志,可以直接丢弃掉. 如果一些可以丢弃,但是又需要知道被丢弃了,可以使用Th ...

  7. 线程池ThreadPoolExecutor里面4种拒绝策略

    ThreadPoolExecutor类实现了ExecutorService接口和Executor接口,可以设置线程池corePoolSize,最大线程池大小,AliveTime,拒绝策略等.常用构造方 ...

  8. Log4j2异步情况下怎么防止丢日志的源码分析以及队列等待和拒绝策略分析

    org.apache.logging.log4j.core.async.AsyncLoggerConfigDisruptor以下所有源码均在此类中首先我们看下log4j2异步队列的初始化 从这里面我们 ...

  9. Android线程池(二)——ThreadPoolExecutor及其拒绝策略RejectedExecutionHandler使用演示样例

    MainActivity例如以下: package cc.vv; import java.util.concurrent.LinkedBlockingQueue; import java.util.c ...

随机推荐

  1. js简单实现promise

    function myPromise(fn){ let status='pending',successCallback=[],failedCallback=[],data=null,reason=n ...

  2. 编写jQuery插件的方法和注意点

    编写jQuery插件的方法和注意点 插件的种类 jQuery的插件主要分为3种类型. 1. 封装对象方法的插件 这种插件是将对象方法封装起来,用于对通过选择器获取的jQuery对象进行操作,是最常见的 ...

  3. Nginx与PHP交互过程 + Nginx与PHP通信的两种方式

    一.Nginx与PHP交互过程的7步走(用户对动态PHP网页访问过程) step1:用户将http请求发送给nginx服务器(用户和nginx服务器进行三次握手进行TCP连接) step2:nginx ...

  4. 深入学习CSS中如何使用定位

    CSS中定位介绍 position属性在英文单词中表示位置的意思,在CSS中主要作用设置元素的定位. CSS中一共有3种定位如下: 属性值 描述 fixed 设置固定定位. relative 设置相对 ...

  5. PAC 代理自动发现简介

    一 简介 1.1 什么是PAC文件 代理自动配置(PAC)文件包含一组用javaScript编码的规则,允许web浏览器确定是将Web流量直接发送到Internet还是通过代理服务器发送        ...

  6. layui treeSelect

    官方地址:https://fly.layui.com/extend/treeSelect/ 下面介绍一下这个插件的使用方法 1.html页面 <div class="layui-inp ...

  7. zabbix 4.04 安装文档 - 基于CentOS 7.6

    1    安装前准备: 1.1   安装JDK 卸载openjdk # rpm -qa | grep java # yum remove java-1.8.0-openjdk # yum remove ...

  8. 一起来立Flag吧!超炫的数据图表分析 2020 年 Java 技术趋势

    引言 2020 来了,第一批 00 后已经 20 岁了,95 后也到了晚婚的年龄,员外的头发也越来越少了,新的一年大家有立下了哪些 Flag ?小伙伴们别急着立 Flag,让员外帮你分析一下哪些技术正 ...

  9. 《C++Primer》第五版习题答案--第一章【学习笔记】

    C++Primer第五版习题解答---第一章 ps:答案是个人在学习过程中书写,可能存在错漏之处,仅作参考. 作者:cosefy Date: 2022/1/7 第一章:开始 练习1.3 #includ ...

  10. sqlserver 存储过程调Api接口

    --开启Sql Server 通讯配置-- sp_configure ; GO RECONFIGURE; GO sp_configure ; GO RECONFIGURE; GO EXEC sp_co ...