java 多线程处理list集合数据的实例应用

众所周知创建线程的三种方式:

  • 继承Thread,重写run方法
  • 实现Runnable接口,重新run方法
  • 实现Callable接口,重写call方法

下面使用Callable,来说一下为什么使用

1.Thread类和Runnable接口都不允许声明检查型异常,也不能定义返回值。没有返回值这点稍微有点麻烦。不能声明抛出检查型异常则更麻烦一些。

2.public void run()方法契约意味着你必须捕获并处理检查型异常。即使你小心地保存了异常信息(在捕获异常时)以便稍后检查,但也不能保证这个类(Runnable对象)的所有使用者都读取异常信息。

3.你也可以修改Runnable实现的getter,让它们都能抛出任务执行中的异常。但这种方法除了繁琐也不是十分安全可靠,你不能强迫使用者调用这些方法,程序员很可能会调用join()方法等待线程结束然后就不管了

但是现在不用担心了,以上的问题终于在1.5中解决了。Callable接口和Future接口的引入以及他们对线程池的支持优雅地解决了这两个问题。

以上来自于https://blog.csdn.net/qq_37338761/article/details/89251663

Runnable是出自jdk1.0,Callable出自jdk1.5,那么,后出的类肯定对于前者有增强。

Callable接口实际上是属于Executor框架中的功能类,Callable接口与Runnable接口的功能类似,但提供了比Runnable更加强大的功能。

  • Callable可以在任务结束的时候提供一个返回值,Runnable无法提供这个功能
  • Callable的call方法分可以抛出异常,而Runnable的run方法不能抛出异常。
  • 运行Callable任务可拿到一个Future对象。

直接上代码

/**
     * 多线程处理list
     *
     * @param list 处理的数据
     * @param errorMsg 业务阻断描述
     * @return resultRecipientList 处理后的数据
     * @date 2022/7/13 16:56
     */
    private List<RecipientInfoDTO> multiThreading(List<RecipientInfoDTO> list, List<String> errorMsg) {
        // 返回的数据
        List<RecipientInfoDTO> resultRecipientList = Lists.newArrayList();
        // 每10条数据开启一条线程
        int threadSize = 10;
        // 总数据条数
        int dataSize = list.size();
        // 线程数
        int threadNum = dataSize / threadSize + 1;
        // 计数器
        CountDownLatch countDownLatch = new CountDownLatch(threadNum);
        // 定义标记,过滤threadNum为整数
        boolean special = dataSize % threadSize == 0;
        // 创建一个线程池
        ExecutorService exec = Executors.newFixedThreadPool(threadNum);
        // 定义一个任务集合
        List<Callable<Boolean>> tasks = Lists.newArrayList();
        // 定义一个任务
        Callable<Boolean> task ;
        // 定义循环处理的i批次数据
        List<RecipientInfoDTO> loopDataList;
        // 确定每条线程的数据
        for (int i = 0; i < threadNum; i++) {
            if (i == threadNum - 1) {
                if (special) {
                    countDownLatch.countDown();
                    break;
                }
                loopDataList = list.subList(threadSize * i, dataSize);
            } else {
                loopDataList = list.subList(threadSize * i, threadSize * (i + 1));
            }
            // 当前循环处理的数据集
            List<RecipientInfoDTO> recipientInfoDTOS = loopDataList;
            task = new Callable<Boolean>() {
                @Override
                public Boolean call() throws Exception {
                    if (ObjectUtils.isNotEmpty(recipientInfoDTOS)) {
                        for (RecipientInfoDTO recipientInfo : recipientInfoDTOS) {
                            // do something 业务逻辑处理
                            // 校验收件地址是否停止服务
                            YtoVerifyOrderDTO ytoVerifyOrderDTO = getYtoVerifyOrderDTO(recipientInfo);
                            if (ytoService.verifyReceivesAddress(ytoVerifyOrderDTO)) {
                                recipientInfo.setMsg("当前收件地址的服务网点暂时停止服务");
                                recipientInfo.setUsable(false);
                                errorMsg.add("当前收件地址的服务网点暂时停止服务");
                                continue;
                            }
                            // 通过校验,返回
                            resultRecipientList.add(recipientInfo);
                        }
                    }
                    return true;
                }
            };
            // 减少计数器的计数,如果计数达到零,则释放所有等待线程。
            // 如果当前计数大于零,则递减。如果新计数为零,则重新启用所有等待线程以进行线程调度。
            countDownLatch.countDown();
            // 任务处理完加入集合
            tasks.add(task);
        }
        try {
            // 执行给定的任务,返回一个 Futures 列表,在所有完成时保存它们的状态和结果。
            // Future.isDone对于返回列表的每个元素都是true 。
            // 请注意,已完成的任务可能已经正常终止,也可能通过引发异常终止。
            // 如果在此操作进行时修改了给定的集合,则此方法的结果是不确定的
            exec.invokeAll(tasks);
            // 等待计数器归零
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 关闭线程池
        exec.shutdown();
        return resultRecipientList;
    }

 

posted @ 2022-07-13 18:07  涉世未深的smile  阅读(2511)  评论(1编辑  收藏  举报