手写单例模式的线程池实践

本文介绍了如何利用线程池处理数据校验失败的情况,确保在无法进行事务回滚时,通过异步线程删除另一数据源的任务。通过设置线程池参数,如核心线程数、最大线程数和队列大小,来避免过多线程创建。采用静态内部类实现的懒汉模式确保线程池的单例,从而保证线程池的唯一性。测试结果显示,非单例情况下创建了多个线程池实例,而单例模式下所有操作共享同一线程池,验证了单例的有效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

由于是两个独立的数据源,没法做事务的回滚。( 这两个数据源是来自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减少到0
                    countDownLatch.await();
                } catch (InterruptedException e) {
                    e.pri
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值