自定义异步任务管理器和线程

news2024/12/22 20:13:00
import com.lancoo.common.utils.Threads;
import com.lancoo.common.utils.spring.SpringUtils;

import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 异步任务管理器
 * 
 * @author lancoo
 */
public class AsyncManager
{
    /**
     * 操作延迟10毫秒
     */
    private final int OPERATE_DELAY_TIME = 10;

    /**
     * 异步操作任务调度线程池
     */
    private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");

    /**
     * 单例模式
     */
    private AsyncManager(){}

    private static AsyncManager me = new AsyncManager();

    public static AsyncManager me()
    {
        return me;
    }

    /**
     * 执行任务
     * 
     * @param task 任务
     */
    public void execute(TimerTask task)
    {
        executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
    }

    /**
     * 停止任务线程池
     */
    public void shutdown()
    {
        Threads.shutdownAndAwaitTermination(executor);
    }
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.*;

/**
 * 线程相关工具类.
 * 
 * @author lancoo
 */
public class Threads
{
    private static final Logger logger = LoggerFactory.getLogger(Threads.class);

    /**
     * sleep等待,单位为毫秒
     */
    public static void sleep(long milliseconds)
    {
        try
        {
            Thread.sleep(milliseconds);
        }
        catch (InterruptedException e)
        {
            return;
        }
    }

    /**
     * 停止线程池
     * 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务.
     * 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数.
     * 如果仍然超時,則強制退出.
     * 另对在shutdown时线程本身被调用中断做了处理.
     */
    public static void shutdownAndAwaitTermination(ExecutorService pool)
    {
        if (pool != null && !pool.isShutdown())
        {
            pool.shutdown();
            try
            {
                if (!pool.awaitTermination(120, TimeUnit.SECONDS))
                {
                    pool.shutdownNow();
                    if (!pool.awaitTermination(120, TimeUnit.SECONDS))
                    {
                        logger.info("Pool did not terminate");
                    }
                }
            }
            catch (InterruptedException ie)
            {
                pool.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }

    /**
     * 打印线程异常信息
     */
    public static void printException(Runnable r, Throwable t)
    {
        if (t == null && r instanceof Future<?>)
        {
            try
            {
                Future<?> future = (Future<?>) r;
                if (future.isDone())
                {
                    future.get();
                }
            }
            catch (CancellationException ce)
            {
                t = ce;
            }
            catch (ExecutionException ee)
            {
                t = ee.getCause();
            }
            catch (InterruptedException ie)
            {
                Thread.currentThread().interrupt();
            }
        }
        if (t != null)
        {
            logger.error(t.getMessage(), t);
        }
    }
}
import com.lancoo.common.utils.Threads;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 线程池配置
 *
 **/
@Configuration
public class ThreadPoolConfig
{
    // 核心线程池大小
    private int corePoolSize = 50;

    // 最大可创建的线程数
    private int maxPoolSize = 200;

    // 队列最大长度
    private int queueCapacity = 1000;

    // 线程池维护线程所允许的空闲时间
    private int keepAliveSeconds = 300;

    @Bean(name = "threadPoolTaskExecutor")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor()
    {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setMaxPoolSize(maxPoolSize);
        executor.setCorePoolSize(corePoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveSeconds);
        // 线程池对拒绝任务(无线程可用)的处理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

    /**
     * 执行周期性或定时任务
     */
    @Bean(name = "scheduledExecutorService")
    protected ScheduledExecutorService scheduledExecutorService()
    {
        return new ScheduledThreadPoolExecutor(corePoolSize,
                new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
                new ThreadPoolExecutor.CallerRunsPolicy())
        {
            @Override
            protected void afterExecute(Runnable r, Throwable t)
            {
                super.afterExecute(r, t);
                Threads.printException(r, t);
            }
        };
    }
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;

/**
 * 确保应用退出时能关闭后台线程
 *
 * @author lancoo
 */
@Component
public class ShutdownManager
{
    private static final Logger logger = LoggerFactory.getLogger("sys-user");

    @PreDestroy
    public void destroy()
    {
        shutdownAsyncManager();
    }

    /**
     * 停止异步执行任务
     */
    private void shutdownAsyncManager()
    {
        try
        {
            logger.info("====关闭后台任务任务线程池====");
            AsyncManager.me().shutdown();
        }
        catch (Exception e)
        {
            logger.error(e.getMessage(), e);
        }
    }
}

调用异步时直接使用

或者直接在方法上使用异步注解@Async

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1302075.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

apisix下自定义 Nginx 配置

apisix下自定义 Nginx 配置 在apisix配置文件/conf/config.yaml中添加nginx配置。生成的nginx.conf配置文件如下&#xff1a;说明&#xff1a; APISIX 会通过 apisix/cli/ngx_tpl.lua 这个模板和 conf/config-default.yaml 加 conf/config.yaml 的配置生成 Nginx 配置文件。 在…

如果将视频转化为gif格式图

1.选择视频转换GIF&#xff1a; 2.添加视频文件&#xff1a; 3.点击“开始”&#xff1a; 4.选择设置&#xff0c;将格式选择为1080P更加清晰&#xff1a; 5.输出后的效果图&#xff1a;

传统渠道与互联网新零售较量中:2023年之后电商如何引流裂变?

传统渠道与互联网新零售较量中&#xff1a;2023年之后电商如何引流裂变&#xff1f; 互联网新零售是指通过互联网技术和数据驱动&#xff0c;打造以消费者为中心、以线上线下融合为特点的全新零售模式&#xff0c;也是近年来电商行业转型升级的必然趋势。目前普通市场竞争激烈…

图解python | 元组

1.Python元组 Python的元组与列表类似&#xff0c;不同之处在于元组的元素不能修改。 元组使用小括号&#xff0c;列表使用方括号。 元组创建很简单&#xff0c;只需要在括号中添加元素&#xff0c;并使用逗号隔开即可。 python 复制代码 tup1 (ByteDance, ShowMeAI, 199…

运动重定向:C-3PO-v1

TeachMe: Three-phase learning framework for robotic motion imitation based on interactive teaching and reinforcement learning解析 摘要1. 简介2. 相关工作2.1 基于编码器-解码器的架构2.2 强化学习 3. 方法3.1 问题表述3.2 NTU-DB3.3 阶段1: 编码器和解码器3.4 阶段2:…

9.静态路由

静态路由 中小型网络都会用到&#xff0c;防火墙核心交换机用的很多&#xff0c;一般是用在出口 路由表&#xff1a;路由器用来转发数据包唯一的依据 NextHop下一跳 Static静态路由需要手动设置 ip route-static 目标网段 掩码 下一跳例如&#xff1a;ip route-static 192…

SD-WAN VS MPLS :怎么选择最合适的网络连接方案?

随着企业网络需求的不断增长&#xff0c;网络连接方案也变得更加多样化。在这种情况下&#xff0c;SD-WAN和MPLS成为了企业考虑的两种主要选择。本文将就SD-WAN和MPLS这两种网络连接方案进行比较&#xff0c;深入探讨它们在成本、体验、部署周期和运维等方面的差异。 1、成本投…

LV.13 D2 开发板启动流程 学习笔记

一、开发板启动过程 EMMC&#xff1a;相当于电脑的外存&#xff0c;断电不丢失 开发板上电后首先运行SOC内部iROM中固化的代码(BL0)&#xff0c;这段代码先对基本的软硬件环境(时钟等...)进行初始化&#xff0c;然后再检测拨码开关位置获取启动方式&#xff0c;然后再将对应存储…

vs vue项目目录说明

vue项目目录结构说明 视图&#xff1a; 主要描述src和依赖配置 src下 assets:存放需要用到的静态资源文件的地方 如css.js.img.view等 commponents:存放一些通用的组件&#xff1b;例&#xff1a;在开发当中如果有需要抽出来的公用模块&#xff0c;可以封装为通用组件&#xf…

AI 绘画 | Stable Diffusion 真实人物动漫二次元化

前言 如何让一张真实人物变成动漫二次元风格的图片?Stable Diffusion WebUI加上contolNet扩展插件帮你快速实现。快来使用AI绘画打开异世界的大门吧!!! 真人动漫化 选择大模型 首先选择一个二次元风格人物画风的大模型(我这里选择是SD1.5通用模型anything-v5-PrtRE.sa…

【数字经济】你必须知道的SABOE数字化转型

【文末送书】今天推荐一本企业管理类前沿书籍《企业架构驱动数字化转型&#xff1a;以架构为中心的端到端转型方法论》 目录 01传统企业数字化转型面临诸多挑战02SABOE数字化转型五环法为企业转型破除迷雾03文末送书 01传统企业数字化转型面临诸多挑战 即将过去的2023年&#…

赛邮云全新改版-SUBMAIL.v4,快来看都有哪些变化吧!

赛邮云全新改版-SUBMAIL.v4&#xff0c;快来看都有哪些变化吧&#xff01; [![](https://img-blog.csdnimg.cn/img_convert/b57c34f9d1732e78d85a73d5f0ec5669.png)](https://libraries.mysubmail.com/public/745bbd47ee09e5810cebad1688282e65/images/a8901d3890dd27fae0745ec…

可以组成网络的服务器 - 华为OD统一考试(C卷)

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 200分 题解&#xff1a; Java / Python / C 题目描述 在一个机房中&#xff0c;服务器的位置标识在n*m的整数矩阵网格中&#xff0c;1表示单元格上有服务器&#xff0c;0表示没有。如果两台服务器位于同一行或者同一列…

git入门教程+常用命令

Git入门教程 本文章主要参照视频教程&#xff1a;https://www.bilibili.com/video/BV1FE411P7B3/?spm_id_from333.337.search-card.all.click&vd_source06caf161b187fb3f4c039bc15e238fea 为什么要使用GIT 版本控制是项目、文档迭代的必然要求&#xff0c;所以需要使用…

traj_dist 笔记:Cython部分(cydist)

1 basic_euclidean.pyx 1.1 cimport 部分 from libc.math cimport sqrt from libc.math cimport fmin #使用 cimport 从 C 的标准库 libc 中导入数学函数 sqrt&#xff08;平方根&#xff09;和 fmin&#xff08;两个浮点数的最小值&#xff09;cimport numpy as np导入 NumP…

张正友相机标定法原理与实现

张正友相机标定法是张正友教授1998年提出的单平面棋盘格的相机标定方法。传统标定法的标定板是需要三维的,需要非常精确,这很难制作,而张正友教授提出的方法介于传统标定法和自标定法之间,但克服了传统标定法需要的高精度标定物的缺点,而仅需使用一个打印出来的棋盘格就可…

Qt开发 之 记一次安装 Qt5.12.12 安卓环境的失败案例

文章目录 1、安装Qt2、安卓开发的组合套件2.1、CSDN地址2.2、官网地址2.3、发现老方法不适用了 3、尝试用新方法解决3.1、先安装JDK&#xff0c;搞定JDK环境变量3.1.1、安装jdk3.1.2、确定jdk安装路径3.1.3、打开系统环境变量配置3.1.4、配置系统环境变量3.1.5、验证JDK环境变量…

白羽肉鸡养殖市场分析:2023年中国市场处于盈利状态

白羽肉鸡是我国养殖的主要快大型肉鸡品种&#xff0c;由于羽毛为白色&#xff0c;相较于本土黄羽肉鸡的羽毛颜色&#xff0c;基层常称其为白羽肉鸡。 隐性白羽鸡属于快大白羽肉鸡。是从白洛克(或白温多得)中选育而成。原产于法国。隐性白羽鸡在优质鸡配套上的应用对我国优质鸡产…

HCIA-H12-811题目解析(5)

1、【单选题】 以下关于Hybrid端口说法正确的有&#xff1f; 2、【单选题】使用命令"vlan batch 10 20"和"valn batch 10 to 20"&#xff0c;分别能创建的vlan数量是&#xff1f;&#xff08;&#xff09; 3、【单选题】二层ACL的编号范围是&#xff1f;…

女士内衣市场分析:预计2028年将达到643.08亿美元

内衣 (英文名:Underwear)&#xff0c;是指贴身穿的衣物。内衣有保暖及污秽的危害作用&#xff0c;有时会被视为性征。女士内衣行业生产的主要原料是各类织布或无纺布&#xff0c;成分有海绵、边、定型纱、骨胶、肩带等&#xff0c;布面料在内衣企业的生产成本中所占比重较大。女…