场景,有两个接口分别会接收两个数据,如果其中一个数据校验失败,那么另一个数据也要删掉。

由于是两个独立的数据源,没法做事务的回滚。( 这两个数据源是来自canal的监听得到的)。

因此考虑的方案就是,当校验不通过的时候,通过异步的方式,去起一个线程去删掉另一个接口过来的任务,但是这两个数据过来会有延时几秒,因此在另一个线程里面,先休眠3秒在执行删除。

因此考虑用一个线程池,防止校验不通过的数据过多导致创建过多的线程让系统出现问题。

线程池的参数:
1.第一个参数是核心线程数 2个
2.第二个参数是最大线程数10个
3.第三个参数是空闲线程存活时间60秒
4.第四个参数是时间单位 秒
5.线程任务队列,设置成了100个任务, 有界队列,如果队列满了,就会创建新的线程 ,最大不超过10个。 如果还有任务,就会执行拒绝策略
6.线程工厂,继承了ThreadFactor ,用于创建线程,设置了线程名称 ,方便后续出问题排查
7.拒绝策略,这里的策略是直接放弃任务,并打印日志。

 new ThreadPoolExecutor(2, 10, 60, TimeUnit.SECONDS, new ArrayBlockingQueue(100),(Runnable r) -> {Thread t = new Thread(r);t.setName("删除校验失败的对帐单关联的保险数据线程");log.info("启动"+t.getName());return new Thread(r);}, (Runnable r, ThreadPoolExecutor executor) -> {log.error("已超出最大任务数,那么校验不通过的对账单数据,狗日的系统出问题了,删不过来了");});

拒绝策略,默认的几种拒绝策略有 1.直接抛异常,2.忽视掉,3.丢掉最老的任务,4.让当初线程执行

这里我们选择忽视掉并打印日志。

得用单例模式,保证线程池的唯一,不至于每一次都创建一个新的线程池。不然这个线程池就没意义了。

懒汉模式,通过静态内部类实现,因类只要用的时候才会被加载,且只加载一次,且加载过程是加锁的(jvm实现)

public class CheckAccountThreadPoolUtil {//静态方法获取对象public static ExecutorService getWorkPoolUtil() {//调用内部静态类的静态方法获取对象 //这个时候触发内部类的加载 也就是只有在用的时候才会加载,懒汉模式return Helper.getInstance();}//内部类加载之后 private static class Helper {//静态字段  在类加载的时候被初始化  且只初始化一次private static ExecutorService instance=new ExecutorService(){}.... ;//获取对象public static ExecutorService getInstance() {return instance;}}

单例和非单例的验证

非单例

public class CheckAccountThreadPoolUtil {public static ExecutorService getWorkPoolUtil() {return Helper.getInstance();}private static class Helper {private static ExecutorService instance;public static ExecutorService getInstance() {if (instance!=null){return instance;}instance = new ThreadPoolExecutor(2, 10, 60, TimeUnit.SECONDS, new ArrayBlockingQueue(100),(Runnable r) -> {Thread t = new Thread(r);t.setName("删除校验失败的对帐单关联的保险数据线程");log.info("启动"+t.getName());return new Thread(r);}, (Runnable r, ThreadPoolExecutor executor) -> {log.error("已超出最大任务数,那么校验不通过的对账单数据,狗日的系统出问题了,删不过来了");});return instance;}}}

十个线程同时获取如下

public static void main(String[] args) throws InterruptedException, IOException {//同时启动10个 看是否是单例CountDownLatch countDownLatch = new CountDownLatch(10);for (int i = 0; i < 10; i++) {new Thread(() -> {log.info("进入等待");countDownLatch.countDown();try {//在这个节点等待countDownLatch减少到0countDownLatch.await();} catch (InterruptedException e) {e.printStackTrace();}log.info("等待结束");System.out.println("executorService:" + CheckAccountThreadPoolUtil.getWorkPoolUtil().hashCode());}).start();System.out.println("启动线程数"+(i+1));}}

结果

启动线程数1
启动线程数2
启动线程数3
启动线程数4
启动线程数5
启动线程数6
启动线程数7
启动线程数8
启动线程数9
启动线程数10
00:05:19.932 [Thread-2] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:05:19.932 [Thread-6] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:05:19.933 [Thread-1] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:05:19.933 [Thread-4] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:05:19.932 [Thread-7] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:05:19.932 [Thread-8] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:05:19.933 [Thread-3] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:05:19.932 [Thread-5] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:05:19.933 [Thread-0] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:05:19.933 [Thread-9] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:05:19.936 [Thread-9] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
00:05:19.936 [Thread-7] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
00:05:19.936 [Thread-4] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
00:05:19.936 [Thread-2] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
00:05:19.936 [Thread-1] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
00:05:19.936 [Thread-8] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
00:05:19.936 [Thread-3] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
00:05:19.936 [Thread-5] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
00:05:19.936 [Thread-6] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
00:05:19.936 [Thread-0] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
executorService:1188407569
executorService:1730989841
executorService:1748713658
executorService:693173612
executorService:2005060830
executorService:1390979302
executorService:2082070238
executorService:1303637660
executorService:2098748826
executorService:1338817235

可以看到,每个hashcode都不一样 。
改成单例之后如下

public class CheckAccountThreadPoolUtil {public static ExecutorService getWorkPoolUtil() {return Helper.getInstance();}private static class Helper {private static ExecutorService instance =new ThreadPoolExecutor(2, 10, 60, TimeUnit.SECONDS, new ArrayBlockingQueue(100),(Runnable r) -> {Thread t = new Thread(r);t.setName("删除校验失败的对帐单关联的保险数据线程");log.info("启动"+t.getName());return new Thread(r);}, (Runnable r, ThreadPoolExecutor executor) -> {log.error("已超出最大任务数,那么校验不通过的对账单数据,狗日的系统出问题了,删不过来了");});public static ExecutorService getInstance() {return instance;}}
}

测试验证代码不变 ,结果如下:

启动线程数1
启动线程数2
启动线程数3
启动线程数4
启动线程数5
启动线程数6
启动线程数7
启动线程数8
启动线程数9
启动线程数10
00:11:20.293 [Thread-3] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:11:20.293 [Thread-4] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:11:20.293 [Thread-9] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:11:20.293 [Thread-0] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:11:20.293 [Thread-2] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:11:20.293 [Thread-1] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:11:20.293 [Thread-7] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:11:20.293 [Thread-5] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:11:20.293 [Thread-6] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:11:20.293 [Thread-8] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
00:11:20.298 [Thread-8] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
00:11:20.298 [Thread-4] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
00:11:20.298 [Thread-0] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
00:11:20.298 [Thread-1] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
00:11:20.298 [Thread-9] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
00:11:20.298 [Thread-5] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
00:11:20.298 [Thread-7] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
00:11:20.298 [Thread-6] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
00:11:20.298 [Thread-2] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
00:11:20.298 [Thread-3] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
executorService:1840045850
executorService:1840045850
executorService:1840045850
executorService:1840045850
executorService:1840045850
executorService:1840045850
executorService:1840045850
executorService:1840045850
executorService:1840045850
executorService:1840045850


package com.souche.sfs.server.common.util;import lombok.extern.slf4j.Slf4j;import java.io.IOException;
import java.util.concurrent.*;/*** @ClassName CheckAccountThreadPoolUtil* @Author laixiaoxing* @Date 2019/5/8 下午4:45* @Description 用来异步删掉校验失败的对账单对应的保险数据的线程池* @Version 1.0*/
@Slf4j
public class CheckAccountThreadPoolUtil {public static ExecutorService getWorkPoolUtil() {return Helper.getInstance();}private static class Helper {private static ExecutorService instance=new ThreadPoolExecutor(2, 10, 60, TimeUnit.SECONDS, new ArrayBlockingQueue(100),(Runnable r) -> {Thread t = new Thread(r);t.setName("删除校验失败的对帐单关联的保险数据线程");log.info("启动"+t.getName());return new Thread(r);}, (Runnable r, ThreadPoolExecutor executor) -> {log.error("已超出最大任务数,那么校验不通过的对账单数据,狗日的系统出问题了,删不过来了");});public static ExecutorService getInstance() {return instance;}}//测试public static void main(String[] args) throws InterruptedException, IOException {//挨个获取多个 看是否是单例System.out.println("顺序启动获取");ExecutorService executorService = CheckAccountThreadPoolUtil.getWorkPoolUtil();System.out.println(executorService.hashCode());ExecutorService executorService2 = CheckAccountThreadPoolUtil.getWorkPoolUtil();System.out.println(executorService2.hashCode());//同时启动10个 看是否是单例CountDownLatch countDownLatch = new CountDownLatch(10);for (int i = 0; i < 10; i++) {new Thread(() -> {log.info("进入等待");//计数器减1countDownLatch.countDown();try {//在这个节点等待countDownLatch减少到0countDownLatch.await();} catch (InterruptedException e) {e.printStackTrace();}log.info("等待结束");System.out.println("executorService:" + CheckAccountThreadPoolUtil.getWorkPoolUtil().hashCode());}).start();System.out.println("启动线程数"+(i+1));}//启动一批线程放进去for (int i = 0; i < 200; i++) {executorService.submit(()->{try {Thread.sleep(5000L);} catch (InterruptedException e) {e.printStackTrace();}});}System.in.read();}}

测试拒绝策略如下

顺序启动获取
314337396
314337396
启动线程数1
启动线程数2
启动线程数3
启动线程数4
启动线程数5
启动线程数6
启动线程数7
启动线程数8
启动线程数9
启动线程数10
23:25:40.656 [Thread-7] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
23:25:40.656 [Thread-3] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
23:25:40.655 [Thread-1] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
23:25:40.656 [Thread-9] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
23:25:40.656 [Thread-2] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
23:25:40.656 [Thread-8] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
23:25:40.656 [Thread-5] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
23:25:40.659 [main] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 启动删除校验失败的对帐单关联的保险数据线程
23:25:40.655 [Thread-0] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
23:25:40.655 [Thread-6] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
23:25:40.656 [Thread-4] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 进入等待
23:25:40.661 [Thread-9] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
23:25:40.661 [Thread-7] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
executorService:314337396
executorService:314337396
23:25:40.661 [Thread-5] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
executorService:314337396
23:25:40.661 [Thread-4] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
executorService:314337396
23:25:40.661 [Thread-2] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
executorService:314337396
23:25:40.661 [Thread-3] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
executorService:314337396
23:25:40.661 [Thread-8] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
executorService:314337396
23:25:40.661 [Thread-1] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
23:25:40.661 [Thread-0] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
executorService:314337396
23:25:40.661 [Thread-6] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 等待结束
executorService:314337396
executorService:314337396
23:25:40.660 [main] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 启动删除校验失败的对帐单关联的保险数据线程
23:25:40.663 [main] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 启动删除校验失败的对帐单关联的保险数据线程
23:25:40.664 [main] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 启动删除校验失败的对帐单关联的保险数据线程
23:25:40.664 [main] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 启动删除校验失败的对帐单关联的保险数据线程
23:25:40.664 [main] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 启动删除校验失败的对帐单关联的保险数据线程
23:25:40.665 [main] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 启动删除校验失败的对帐单关联的保险数据线程
23:25:40.665 [main] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 启动删除校验失败的对帐单关联的保险数据线程
23:25:40.665 [main] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 启动删除校验失败的对帐单关联的保险数据线程
23:25:40.665 [main] INFO com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 启动删除校验失败的对帐单关联的保险数据线程
23:25:40.665 [main] ERROR com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 已超出最大任务数,那么校验不通过的对账单数据,狗日的系统出问题了,删不过来了
23:25:40.665 [main] ERROR com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 已超出最大任务数,那么校验不通过的对账单数据,狗日的系统出问题了,删不过来了
23:25:40.665 [main] ERROR com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 已超出最大任务数,那么校验不通过的对账单数据,狗日的系统出问题了,删不过来了
23:25:40.665 [main] ERROR com.souche.sfs.server.common.util.CheckAccountThreadPoolUtil - 已超出最大任务数,那么校验不通过的对账单数据,狗日的系统出问题了,删不过来了

手写单例模式的线程池实践相关推荐

  1. python是如何实现进程池和线程池的_高并发:线程、线程锁与线程池(精华),手写代码实现线程池...

    前文: 单线程--多线程的开启--线程锁--线程同步工具--手写连接池--连接池工具类. 一.线程 1.线程的概念 2.线程与进程的关系 3.定义: 区别:如上!!! 4.wait()和sleep() ...

  2. 高并发:线程、线程锁与线程池(精华),文中附上一个手写代码实现线程池视频(c/c++语言)

    前文: 单线程--多线程的开启--线程锁--线程同步工具--手写连接池--连接池工具类. 一.线程 1.线程的概念 2.线程与进程的关系 3.定义: 区别:如上!!! 4.wait()和sleep() ...

  3. Linux环境,C/C++语言手写代码实现线程池

    前言 在我们日常生活中会遇到许许多多的问题,如果一个服务端要接受很多客户端的数据,该怎么办?多线程并发内存不够怎么办?所以我们需要了解线程池的相关知识. 一.线程池是什么? 1.线程池的简介 线程池是 ...

  4. 美团动态线程池实践思路,开源了

    大家好,今天我们来聊一个比较实用的话题,动态可监控的线程池实践,全新开源项目(DynamicTp)地址在文章末尾,欢迎交流学习. 写在前面 稍微有些Java编程经验的小伙伴都知道,Java的精髓在ju ...

  5. 美团动态线程池实践思路已开源

    项目地址 gitee地址:gitee.com/yanhom/dyna- github地址:github.com/lyh200/dyna- 系列文章 动态线程池框架(DynamicTp),监控及源码解析 ...

  6. 今天我们来聊一个比较实用的话题,动态可监控的线程池实践,全新开源项目

    大家好,今天我们来聊一个比较实用的话题,动态可监控的线程池实践,全新开源项目(DynamicTp)地址在下方,欢迎star交流学习. 项目地址 gitee地址:gitee.com/yanhom/dyn ...

  7. 美团动态线程池实践思路开源项目(DynamicTp),线程池源码解析及通知告警篇

    大家好,这篇文章我们来聊下动态线程池开源项目(DynamicTp)的通知告警模块.目前项目提供以下通知告警功能,每一个通知项都可以独立配置是否开启.告警阈值.告警间隔时间.平台等,具体代码请看core ...

  8. 使用代理模式手写简单的数据库连接池

    使用代理模式手写简单的数据库连接池 JDBC直连数据库 思考 改造 ConnectionProxy ConnectionPool ProxyMain 运行结果 代理模式 与装饰器的区别 JDBC直连数 ...

  9. 面试官问:你做过什么Java线程池实践,我写了一篇博客给他看~

    线程池大家都## 标题很熟悉,无论是平时的业务开发还是框架中间件都会用到,大部分都是基于JDK线程池ThreadPoolExecutor做的封装, 都会牵涉到这几个核心参数的设置:核心线程数,等待(任 ...

最新文章

  1. 吴恩达家免费 NLP 课程重磅上线!110 个小视频教你做出聊天机器人,粉丝:我要让娃跟吴恩达姓!...
  2. 干货整理!10个Python图像处理工具,入门必看,提效大法
  3. Javascript 基础-------this关键字
  4. Python - 关于方法参数和字典更新(dict.update())方法
  5. 亿级别记录的mongodb批量导入Es的java代码完整实现
  6. 《架构师(“拥抱2015”特刊)》发布
  7. java鼠标进入高亮效果_鼠标选中文本划词高亮、再次选中划词取消高亮效果
  8. Github Pages 搭建个人网站
  9. Flask中的session操作
  10. C++的流输入和输出操作
  11. DFF之--(一)神经网络入门之线性回归
  12. png文件合并_程序员学习之在Python中使用PDF:阅读、旋转、合并和拆分
  13. 大数据行业发展迅速的原因
  14. 【信号处理】语音时域频域频谱图分析含Matlab源码
  15. linux下RabbitMQ的配置和安装
  16. 如何理解泊松分布和泊松过程
  17. [Leetcode] 382. Linked List Random Node 解题报告
  18. 【Ajax】第一课 Ajax访问Servlet解析Json格式
  19. CUDA编程之环境配置
  20. linux 打开终端自动运行脚本.barshrc

热门文章

  1. kafka Streams
  2. 【Reference Reading】评估多模态影像(CT, MRI和PET)在phantom和头颈部癌症患者的配准程序:准确性,重现性和一致性
  3. 舞美设计在舞台中应用的重要性
  4. 4年功能测试跳槽,最后选择了学习自动化测试,月薪18K实现逆袭
  5. 矩阵期望 matlab,matlab中矩阵元素求和、求期望和均方差
  6. html ajax实现分页代码,用jQuery中的ajax分页实现代码
  7. 橄榄文案:卖橄榄的水果文案,橄榄水果发圈文案
  8. wxid转成微信账号
  9. vivo请来宋仲基做代言 这是要边撩妹边搞机啊
  10. JS逆向之某头条jsvmp逻辑层算法分析