Java 多线程永动任务设计与实现

本文介绍了如何在Java中设计和实现一个支持多线程的永动异步任务系统,包括使用线程池进行并发控制、优雅关闭任务的策略以及具体的任务执行流程。内容涵盖线程池的创建、任务数据的获取与处理、任务的单个实例实现、任务入口的创建以及执行结果的分析。
摘要由CSDN通过智能技术生成

1. 功能说明

做这个多线程异步任务,主要是因为我们有很多永动的异步任务,什么是永动呢?就是任务跑起来后,需要一直跑下去。

比如消息 Push 任务,因为一直有消息过来,所以需要一直去消费 DB 中的未推送消息,就需要整一个 Push 的永动异步任务。

我们的需求其实不难,简单总结一下:

能同时执行多个永动的异步任务;
每个异步任务,支持开多个线程去消费这个任务的数据;
支持永动异步任务的优雅关闭,即关闭后,需要把所有的数据消费完毕后,再关闭。

完成上面的需求,需要注意几个点:

  • 每个永动任务,可以开一个线程去执行;
  • 每个子任务,因为需要支持并发,需要用线程池控制;
  • 永动任务的关闭,需要通知子任务的并发线程,并支持永动任务和并发子任务的优雅关闭。

2. 多线程任务示例
2.1 线程池

对于子任务,需要支持并发,如果每个并发都开一个线程,用完就关闭,对资源消耗太大,所以引入线程池:


public class TaskProcessUtil {
   
    // 每个任务,都有自己单独的线程池
    private static Map<String, ExecutorService> executors =
        new ConcurrentHashMap<>();

    // 初始化一个线程池
    private static ExecutorService init(String poolName, int poolSize) {
   
        return new ThreadPoolExecutor(poolSize, poolSize, 0L,
            TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(),
            new ThreadFactoryBuilder()
                .setNameFormat("Pool-" + poolName)
                .setDaemon(false)
                .build(),
            new ThreadPoolExecutor.CallerRunsPolicy());
    }

    // 获取线程池
    public static ExecutorService getOrInitExecutors(
        String poolName, int poolSize) {
   
        ExecutorService executorService = executors.get(poolName);
        if (null == executorService) {
   
            synchronized (TaskProcessUtil.class) {
   
                executorService = executors.get(poolName);
                if (null == executorService) {
   
                    executorService = init(poolName, poolSize);
                    executors.put(poolName, executorService);
                }
            }
        }
        return executorService;
    }

    // 回收线程资源
    public static void releaseExecutors(String poolName) {
   
        ExecutorService executorService = executors.remove(poolName);
        if (executorService != null) {
   
            executorService.shutdown();
        }
    }
}

这是一个线程池的工具类。这里初始化线程池和回收线程资源很简单,我们主要讨论获取线程池。

获取线程池可能会存在并发情况,所以需要加一个 synchronized 锁。锁住后,需要对 executorService 进行二次判空校验

2.2 单个任务

为了更好讲解单个任务的实现方式,我们的任务主要就是把 Cat 的数据打印出来,Cat 定义如下:


@Data
@Service
public class Cat {
   
    private String catName;
    public Cat 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值