• 关于Java多线程处理List数据


    一、背景

    多线程数量的问题,一般情况下,多线程数量要等于机器CPU核数-1。

    二、实例

    1、解决问题:如何让n个线程顺序遍历含有n个元素的List集合

    import java.util.ArrayList;
    import java.util.List;
    import org.apache.commons.lang3.ArrayUtils;
    
    public class Test_4 {
        /**
         * 多线程处理list
         *
         * @param data  数据list
         * @param threadNum  线程数
         */
        public synchronized void handleList(List<String> data, int threadNum) {
            int length = data.size();
            int tl = length % threadNum == 0 ? length / threadNum : (length
                    / threadNum + 1);
    
            for (int i = 0; i < threadNum; i++) {
                int end = (i + 1) * tl;
                HandleThread thread = new HandleThread("线程[" + (i + 1) + "] ",  data, i * tl, end > length ? length : end);
                thread.start();
            }
        }
    
        class HandleThread extends Thread {
            private String threadName;
            private List<String> data;
            private int start;
            private int end;
    
            public HandleThread(String threadName, List<String> data, int start, int end) {
                this.threadName = threadName;
                this.data = data;
                this.start = start;
                this.end = end;
            }
    
            public void run() {
                List<String> subList = data.subList(start, end)/*.add("^&*")*/;
                System.out.println(threadName+"处理了"+subList.size()+"条!");
            }
    
        }
    
        public static void main(String[] args) {
            Test_4 test = new Test_4();
            // 准备数据
            List<String> data = new ArrayList<String>();
            for (int i = 0; i < 6666; i++) {
                data.add("item" + i);
            }
            test.handleList(data, 5);
            System.out.println(ArrayUtils.toString(data));
        }
    }

    2、List多线程并发读取读取现有的list对象

    //测试读取List的线程类,大概34秒
    package com.thread.list;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class Main {
    
        public static void main(String[] args) {
    
            List<String> list = new ArrayList<String>();
            Map<Long,Integer> map = new HashMap<Long,Integer>();
    
            for(int i = 0;i<1000;i++){
                list.add(""+i);
            }
    
            int pcount = Runtime.getRuntime().availableProcessors();
            long start = System.currentTimeMillis();
    
            for(int i=0;i<pcount;i++){
    
               Thread t = new MyThread1(list,map);
                map.put(t.getId(),Integer.valueOf(i));
                t.start();
                try {
                    t.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
               // System.out.println(list.get(i));
            }
            System.out.println("----"+(System.currentTimeMillis() - start));
        }
    }
    
    //线程类
    package com.thread.list;
    
    import java.util.List;
    import java.util.Map;
    
    public class MyThread1 extends Thread {
    
        private List<String> list;
        private Map<Long,Integer> map;
    
        public MyThread1(List<String> list,Map<Long,Integer> map){
            this.list = list;
            this.map = map;
        }
    
        @Override
        public void run() {
    
            int pcount = Runtime.getRuntime().availableProcessors();
            int i = map.get(Thread.currentThread().getId());
    
            for(;i<list.size();i+=pcount){
                System.out.println(list.get(i));
            }
        }
    }

    3、多线程分段处理List集合

    场景:大数据List集合,需要对List集合中的数据同标准库中数据进行对比,生成新增,更新,取消数据。

    解决方案:

    a、List集合分段;

    b、动态创建线程池newFixedThreadPool;

    c、将对比操作在多线程中实现;

    public static void main(String[] args) throws Exception {
    
            // 开始时间
            long start = System.currentTimeMillis();
            List<String> list = new ArrayList<String>();
    
            for (int i = 1; i <= 3000; i++) {
                list.add(i + "");
            }
            // 每500条数据开启一条线程
            int threadSize = 500;
            // 总数据条数
            int dataSize = list.size();
            // 线程数
            int threadNum = dataSize / threadSize + 1;
            // 定义标记,过滤threadNum为整数
            boolean special = dataSize % threadSize == 0;
    
            // 创建一个线程池
            ExecutorService exec = Executors.newFixedThreadPool(threadNum);
            // 定义一个任务集合
            List<Callable<Integer>> tasks = new ArrayList<Callable<Integer>>();
            Callable<Integer> task = null;
            List<String> cutList = null;
    
            // 确定每条线程的数据
            for (int i = 0; i < threadNum; i++) {
                if (i == threadNum - 1) {
                    if (special) {
                        break;
                    }
                    cutList = list.subList(threadSize * i, dataSize);
                } else {
                    cutList = list.subList(threadSize * i, threadSize * (i + 1));
                }
                // System.out.println("第" + (i + 1) + "组:" + cutList.toString());
                final List<String> listStr = cutList;
                task = new Callable<Integer>() {
    
                    @Override
                    public Integer call() throws Exception {
                        System.out.println(Thread.currentThread().getName() + "线程:" + listStr);
                        return 1;
                    }
                };
                // 这里提交的任务容器列表和返回的Future列表存在顺序对应的关系
                tasks.add(task);
            }
    
            List<Future<Integer>> results = exec.invokeAll(tasks);
    
            for (Future<Integer> future : results) {
                System.out.println(future.get());
            }
    
            // 关闭线程池
            exec.shutdown();
            System.out.println("线程任务执行结束");
            System.err.println("执行任务消耗了 :" + (System.currentTimeMillis() - start) + "毫秒");
        }
  • 相关阅读:
    Word自带的文献管理功能的具体实现步骤
    线程通信中的细节问题
    Java中static方法、程序入口函数main方法的继承问题
    Android中模拟器启动中出现“emulator-arm.exe已停止工作”
    CMD命令详解
    jQuery实现回到顶部功能
    Toad&PL/SQL修改查询信息
    TOAD常用快捷键
    ORACLE WITH AS 用法
    常用快捷键(转)
  • 原文地址:https://www.cnblogs.com/ZJOE80/p/14385211.html
Copyright © 2020-2023  润新知