Java多线程处理并汇总处理结果

Java多线程处理并汇总处理结果

简介

在业务逻辑处理时,经常会for循环处理多条数据(如2000条),当每一条数据处理时间略微长时(0.1s),整体时间就会比较长了(200s)
如果开10个线程处理时,整体时间就可以缩短10倍,整体只需要20s就可以完成了
因此,本篇文章就介绍一下如何更好的多线程处理,以缩短处理时间

1、示例代码

package ins.claim.simplecase.service;

import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ListeningExecutorService;
import ins.platform.common.util.CompletableFutureUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

@Slf4j
@Service
public class TestThreadService {

    @Autowired
    private ListeningExecutorService threadPool;


    /**
     * @Author Author 
     * @Description 测试入口
     * @Date 16:58 2023/11/24
     * @Param []
     * @return java.util.List<java.util.Map<java.lang.String,java.lang.String>>
     **/
    public List<Map<String, String>> test(){
        // 1、组装请求数据
        List<Map<String, String>> dataList = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            Map<String, String> map = new HashMap<>();
            map.put("1", "0");
            dataList.add(map);
        }
        // 2、多线程处理数据,并返回
        return this.deal(dataList);
    }

    /**
     * @Author Author 
     * @Description 分开多次线程处理
     * @Date 16:50 2023/11/24
     * @Param [list]
     * @return java.util.List<java.util.Map<java.lang.String,java.lang.String>>
     **/
    private List<Map<String, String>> deal(List<Map<String, String>> list){
        // 处理后返回的结果数据
        List<Map<String, String>> result = new ArrayList<>();
        // 每个线程处理的数据条数(可以自定义)
        int threadSize = 50;
        // 判断是否要开线程,计算需要开的线程个数,并依次处理
        if (list != null && list.size() > threadSize)
        {
            List<CompletableFuture<List<Map<String, String>>>> threadResultList = Lists.newArrayList();
            // 计算开几个线程,每个线程处理 threadSize 条
            int threadCount = (list.size() / threadSize) + 1;
            // 循环需要开的线程个数,并处理
            for (int i = 0; i < threadCount; i++) {
                String rid = "日志信息" + i;
                log.info("多线程处理第{}个线程", i);
                if (i == threadCount - 1)
                {
                    // 最后一次 开线程 处理
                    List<Map<String, String>> subList = list.subList(threadSize * i, list.size());
                    threadResultList.add(CompletableFuture.supplyAsync(() -> threadDealOnce(subList, rid), threadPool).exceptionally(ex -> {
                        log.error("线程处理失败了,请查看原因:", ex);
                        return null;
                    }));
                }
                else
                {
                    // 开单个线程
                    List<Map<String, String>> subList = list.subList(threadSize * i, threadSize * (i + 1));
                    threadResultList.add(CompletableFuture.supplyAsync(() -> threadDealOnce(subList, rid), threadPool).exceptionally(ex -> {
                        log.error("线程处理失败了,请查看原因:", ex);
                        return null;
                    }));
                }
            }

            // 多个线程处理后,结果合并处理
            for (List<Map<String, String>> resultOnce : CompletableFutureUtils.futureList(threadResultList)) {
                result.addAll(resultOnce);
            }
        }
        else
        {
            // 不开线程,一次性处理
            result = threadDealOnce(list, "");
        }

        return result;
    }

    /**
     * @Author Author 
     * @Description 单次线程处理的方法(真实的业务方法)
     * @Date 16:49 2023/11/24
     * @Param [list, rid]
     * @return java.util.List<java.util.Map<java.lang.String,java.lang.String>>
     **/
    private List<Map<String, String>> threadDealOnce(List<Map<String, String>> list, String rid){
        log.info("单次线程处理的方法日志开始{}", rid);
        if (list != null && list.size() > 0) {
            int i = 0;
            for (Map<String, String> map : list) {
                log.info("单次线程处理的方法日志{}", rid + "-" + i);
                map.put("2", rid + i);
                i++;
            }
        }

        return list;
    }
}

/**
 * @Description 多线程处理数据测试
 * @return
 * @throws ParseException
 */
@RequestMapping("/testThreadDealData")
public List<Map<String, String>> testThreadDealData() throws Exception {
	List<Map<String, String>> result = testThreadService.test();
	return result;

}

2、线程池设置

服务启动时,需配置好线程池

import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.*;

/**
 * 在于Spring启动时自动加载一个ExecutorService对象. 得到一个20线程的线程池
 */
@Configuration
public class ThreadPoolConfig {

    /**
     * 该线程池使用的时候,不允许手动关闭,生命周期与应用绑定
     */
    @Bean
    public ListeningExecutorService getThreadPool(){
        ThreadFactory basicThreadFactory = new BasicThreadFactory.Builder().namingPattern("basicThreadFactory-ThreadPoolConfig").build();
        ListeningExecutorService pool = new MdcDelegateThreadPoolExecutor(MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(20, basicThreadFactory)));
        return pool;
    }

}

import com.google.common.util.concurrent.AbstractListeningExecutorService;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.sinosoft.fragins.framework.constance.ClmConstants;
import com.sinosoft.fragins.framework.utils.UUIDUtils;
import org.slf4j.MDC;

import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

/**
 * @Author Author 
 * @Description MDC rid 线程委托类(目的:rid 区分一下 主线程和子线程)
 * @Date 16:00 2023/11/6
 * @Param 
 * @return 
 **/
public class MdcDelegateThreadPoolExecutor extends AbstractListeningExecutorService {

    private ListeningExecutorService delegate;


    public MdcDelegateThreadPoolExecutor(ListeningExecutorService delegate) {
        this.delegate = delegate;
    }

    @Override
    public ListenableFuture<?> submit(Runnable task) {
        return delegate.submit(new MdcDelegateRunnable(task));
    }

    @Override
    public <T> ListenableFuture<T> submit(Callable<T> task) {
        return delegate.submit(new MDCDelegateCallable<>(task));
    }

    @Override
    public void shutdown() {
        delegate.shutdown();
    }

    @Override
    public List<Runnable> shutdownNow() {
        return delegate.shutdownNow();
    }

    @Override
    public boolean isShutdown() {
        return delegate.isShutdown();
    }

    @Override
    public boolean isTerminated() {
        return delegate.isTerminated();
    }

    @Override
    public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
        return delegate.awaitTermination(timeout, unit);
    }

    @Override
    public void execute(Runnable command) {
        delegate.execute(command);
    }


    class MDCDelegateCallable<V> implements Callable<V> {

        private String mainThreadRid;

        private Callable<V> delegate;

        public MDCDelegateCallable(Callable<V> callable) {
            this.mainThreadRid = MDC.get(ClmConstants.TRACE_ID_KEY);
            this.delegate = callable;
        }

        @Override
        public V call() throws Exception {
            MDC.put(ClmConstants.TRACE_ID_KEY, mainThreadRid + "-" + UUIDUtils.get12UUID());
            V ret = delegate.call();
            MDC.remove(ClmConstants.TRACE_ID_KEY);
            return ret;
        }
    }

    class MdcDelegateRunnable implements Runnable {

        // 主线程rid
        private String mainThreadRid;

        private Runnable delegate;

        /**
         * @Author Author 
         * @Description 构造器
         * @Date 16:01 2023/11/6
         * @Param [runnable]
         * @return
         **/
        public MdcDelegateRunnable(Runnable runnable) {
            this.mainThreadRid = MDC.get(ClmConstants.TRACE_ID_KEY);
            this.delegate = runnable;
        }

        @Override
        public void run() {
            MDC.put(ClmConstants.TRACE_ID_KEY, mainThreadRid + "-" + UUIDUtils.get12UUID());
            delegate.run();
            MDC.remove(ClmConstants.TRACE_ID_KEY);
        }
    }
}

  • 10
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java多线程结果汇总是指将多个线程并发执行的结果进行汇总和合并。在多线程编程中,我们常常需要将每个线程的计算结果进行累加、合并或者统计等操作,从而得到最终的结果。 一种常见的做法是使用线程池来管理线程的执行。我们可以将任务分解为多个子任务,每个子任务由一个线程来执行。线程池会自动管理线程的创建、执行和销毁,确保我们可以高效地使用线程资源。每个线程计算完毕后,将结果返回给线程池,线程池就可以将这些结果进行合并、汇总,得到最终的结果。 另一种常见的方法是使用Future和Callable来获取线程的执行结果。Callable是一个带有返回值的任务,我们可以使用它来定义每个子任务的逻辑。将Callable提交给线程池后,会返回一个Future对象,我们可以通过该对象获取线程执行的结果。Future提供了方法来判断任务是否已经完成、获取任务的结果等操作。通过迭代每个Future对象,可以将所有的结果进行汇总和合并。 除了线程池和Future,还可以使用线程间的通信来实现结果汇总。比如,可以使用共享变量、信号量、锁等机制来实现各个线程之间的同步和通信。每个线程将计算结果保存在共享变量中,其他线程根据需要读取这些结果,并在必要时进行合并。 无论使用哪种方法,Java多线程结果汇总都需要考虑线程安全性。多个线程同时操作共享的数据结构,可能会引发并发问题,如线程安全、死锁等。为了保证结果的正确性和一致性,我们需要使用适当的同步机制来确保线程的顺序执行和结果的正确性。 总之,通过线程池和Future、线程间通信等手段,可以有效地实现Java多线程结果的汇总和合并,从而提高程序的性能和效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值