java多线程处理list,速度提升嗖嗖的!

目录

项目场景

问题描述

解决方案:

方法一:没有返回值,直接在任务里完成计算

方法二:有返回值

最后


项目场景

前台通过模板批量上传数据到后台


问题描述

后台使用常规方法处理数据,效率低下


解决方案:

使用多线程线程池实现

方法一:没有返回值,直接在任务里完成计算

package com.lwk.test;


import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ThreadPoolExample {

    public static void main(String[] args) throws InterruptedException {
        // 创建一个包含 10 个线程的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        // 创建一个包含 10000 个元素的 List
        List list = new ArrayList<>();
        for (int i = 0; i < 10001; i++) {
            list.add(i);
        }

        // 将 List 分成 10 个子 List,每个子 List 包含 1000 个元素
        List> subLists = new ArrayList<>();
        int subListSize = 1000;
        for (int i = 0; i < list.size(); i += subListSize) {
            subLists.add(list.subList(i, Math.min(i + subListSize, list.size())));
        }

        // 提交每个子 List 的处理任务给线程池
        for (List subList : subLists) {
            executorService.submit(new Task(subList));
        }

        // 等待线程池中所有任务执行完毕
        executorService.shutdown();
        executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);

        // 打印处理结果
        System.out.println("List size: " + list.size());
        System.out.println("Sum of elements: " + Task.getSum());
    }

    static class Task implements Runnable {
        private List list;
        private static long sum = 0;

        public Task(List list) {
            this.list = list;
        }

        @Override
        public void run() {
            long subSum = 0;
            for (int i : list) {
                subSum += i;
            }
            synchronized (Task.class) {
                sum += subSum;
            }
        }

        public static long getSum() {
            return sum;
        }
    }
}

方法二:有返回值

除了创建线程池和分割 List 的过程外,主要的变化是将 Task 类改为实现 Callable 接口,并返回子 List 的和。使用 CompletionService 提交任务和获取任务执行结果,从而减少了线程池等待时间提高执行效率。最后,将每个子 List 的和累加起来,打印处理结果。

package com.lwk.test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class ThreadPoolExample2 {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        // 创建一个包含 10 个线程的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        // 创建一个 CompletionService,用于提交任务和获取任务执行结果
        CompletionService completionService = new ExecutorCompletionService<>(executorService);

        // 创建一个包含 10000 个元素的 List
        List list = new ArrayList<>();
        for (int i = 0; i < 10001; i++) {
            list.add(i);
        }

        // 将 List 分成 10 个子 List,每个子 List 包含 1000 个元素
        List> subLists = new ArrayList<>();
        int subListSize = 1000;
        for (int i = 0; i < list.size(); i += subListSize) {
            subLists.add(list.subList(i, Math.min(i + subListSize, list.size())));
        }

        // 提交每个子 List 的处理任务给 CompletionService
        for (List subList : subLists) {
            completionService.submit(new Task(subList));
        }

        // 获取每个任务的执行结果,并将结果累加起来
        long sum = 0;
        for (int i = 0; i < subLists.size(); i++) {
            Future future = completionService.take();
            sum += future.get();
        }

        // 打印处理结果
        System.out.println("List size: " + list.size());
        System.out.println("Sum of elements: " + sum);

        // 关闭线程池
        executorService.shutdown();
    }

    static class Task implements Callable {
        private List list;

        public Task(List list) {
            this.list = list;
        }

        @Override
        public Long call() throws Exception {
            long subSum = 0;
            for (int i : list) {
                subSum += i;
            }
            return subSum;
        }
    }
}

最后

如果改为项目中使用的话,需要将 【创建一个包含 10000 个元素的 List】改为自己的数据集即可!

需要注意的是:在使用线程池时,需要选择合适的线程池大小,以避免创建过多的线程导致系统资源耗尽!

还有一点:也不要盲目的去开多个线程。如果你的服务器是单cpu单核开多线程反而会增加上下文损耗,从而降低程序执行效率。能开多少个线程,理论是这样计算的:逻辑cpu个数 = (物理cpu个数 * 每个cpu的核心数 * 超线程数),命令见如下

1.查看物理cpu个数,也就是实物cpu的个数

cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l

2.查看每个cpu的core,也就是常说的核心数

cat /proc/cpuinfo| grep "cpu cores"| uniq

今天的分享就到这里了,如果问题欢迎留言指正! 

你可能感兴趣的:(java)