使用CountDownLatch进行并发处理

比如后台需要并发刷新很多元素,逐个刷新比较慢,可以使用CountDownLatch进行并发刷新。

当请求特别多时候,很容易造成线程池满,此时应该考虑有一种线程保护机制,采用快速失败的方式对外抛出特定的异常。

上层业务感知该异常后,可提示前端繁忙,请稍后再试一试。

线程保护机制是创建线程执行器时候,采用SynchronousQueue队列,当请求超过线程池最大队列时候,线程池会直接抛出RejectedExecutionException,说明系统繁忙,此时应该通过限流的方式处理。

一、建立线程池工厂

public class ElementRefreshThreadFactory implements ThreadFactory {
    private static final AtomicInteger poolNumber = new AtomicInteger(1);

    protected final AtomicInteger threadNumber = new AtomicInteger(1);
    protected final ThreadGroup group;
    protected final String namePrefix;
    protected final boolean isDaemon;

    public ElementRefreshThreadFactory() {
        this("ElementRefresher");
    }

    public ElementRefreshThreadFactory(String name) {
        this(name, true);
    }

    public ElementRefreshThreadFactory(String preffix, boolean daemon) {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
        namePrefix = preffix + "-" + poolNumber.getAndIncrement() + "-thread-";
        isDaemon = daemon;
    }

    public Thread newThread(Runnable r) {
        Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
        t.setContextClassLoader(NamedThreadFactory.class.getClassLoader());
        t.setPriority(Thread.MAX_PRIORITY);
        t.setDaemon(isDaemon);
        return t;
    }
}

二、构建线程池及线程执行器

 这里提示系统繁忙需要由线程执行器抛出RejectedExecutionException,由业务系统捕获后封装成自己的系统忙异常再抛出到上层业务。

/**
使用 SynchronousQueue,同步队列,当请求数量突破极限1200个线程后,采用快速失败,提示系统繁忙,请重试的方式。
     */
    private final static ThreadFactory threadFactory = new ElementRefreshThreadFactory();
    private final static ThreadPoolExecutor elementsRefreshExcutor = new ThreadPoolExecutor(100, 1200,
        60L, TimeUnit.SECONDS,
        new SynchronousQueue<>(), threadFactory);

三、使用CountDownLatch并发处理

这一段代码并发刷新一些元素,注意如果线程中有处理失败的,此时一定要在finally中释放countDownLatch的数量。

public List<DisplayElementVo> refreshElements(ServiceContext context, List<DisplayElementVo> sceneElements) {
        if (CollectionUtils.isEmpty(sceneElements)) {
            return null;
        }
        List<DisplayElementVo> dispalyElements = new CopyOnWriteArrayList<>();
        // 支持并发刷新所有元素
        CountDownLatch countDownLatch = new CountDownLatch(sceneElements.size());
        try {
            for (DisplayElementVo element : sceneElements) {
                elementsRefreshExcutor.execute(() -> {
                    try {
                        DisplayElementVo dispalyElement = this.refreshElement(context, element);
                        if (null != dispalyElement) {
                            dispalyElements.add(dispalyElement);
                        } else {
                            log.warn("refreshElementNull ,elementId:{}", element.getId());
                        }
                    } catch(Exception e) {} finally {
                        countDownLatch.countDown();
                    }
                });
            }
        } catch (RejectedExecutionException e) {
            log.error("conCurrentRefreshElementsFailed ", e);
            //抛出一个业务自定义的系统忙异常给到上层业务
            throw new ServiceSystemException(CommonErrorCode.SYSTEM_BUSY);
            // 这里是否要把所有的count全部释放????笔者也没有试验过。
        }
        try {
            // 阻塞等待所有线程执行完成
            countDownLatch.await();
        } catch (InterruptedException e) {
            log.error("timeOutRefresh elements", e);
        }
        return dispalyElements;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值