多线程与线程池demo

news2025/1/16 19:00:04

第一步:切割数据的方法

   public static List<List<Integer>> getProcessData(Integer batchSize) {
        List<Integer> originData = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            originData.add(i);
        }
        List<List<Integer>> processData = ListUtils.partition(originData, batchSize);
        System.out.println(processData.size());
        return processData;
    }

1.入参是 batchSize,我们想要切割的大小(这里设置的是5)
2.然后for循环添加入我们的List数组originData中
3.ListUtils.partition是分割方法,这里既按照batchSize吧0-99分为固定的份数丢入我们的List<List> 中如上所示,拆成了二十份数据

ListUtils.partition的源码解释,意思就是把abcde的list数组拆成List<List>的格式
在这里插入图片描述

第二步: 单线程转换数据的方法

public static List<String> processOneThread(List<Integer> req) throws InterruptedException {
        List<String> output = new ArrayList<>();
        for (Integer value : req) {
            output.add(String.valueOf(value+ 1));
        }
        Thread.sleep(200);
        return output;
    }

单线程数据处理,把List类型转换为List类型
1.入参是 List req
2.通过for循环的方式以及String.valueof把int类型转换为String类型,这里value+1的原因是切割数据的方法是从0开始的,下标我们就要+1让他有数据。
3.Thread.sleep睡眠的原因是为了更好的区分度
4.最终出参的形式是List

第三步:多线程调用


    public static List<String> processByMultiThread(Integer batchSize) throws ExecutionException, InterruptedException {
        List<String> output = new ArrayList<>();

        // 获取分批数据
        List<List<Integer>> batchProcessData = getProcessData(batchSize);

        // 启动线程
        List<FutureTask<List<String>>> futureTaskList = new ArrayList<>();
        for (List<Integer> processData : batchProcessData) {
            Callable<List<String>> callable = () -> processOneThread(processData);
            FutureTask<List<String>> futureTask = new FutureTask<>(callable);
            new Thread(futureTask).start();
            // 启动线程
            futureTaskList.add(futureTask);
        }

        // 获取线程返回的数据
        for (FutureTask futureTask : futureTaskList) {
	            List<String> processData = (List<String>) futureTask.get();
	            output.addAll(processData);
        }
        return output;
    }

主要解析代码

List<FutureTask<List<String>>> futureTaskList = new ArrayList<>();
        for (List<Integer> processData : batchProcessData) {
            Callable<List<String>> callable = () -> processOneThread(processData);
            FutureTask<List<String>> futureTask = new FutureTask<>(callable);
            new Thread(futureTask).start();
            // 启动线程
            futureTaskList.add(futureTask);
        }
List<FutureTask<List<String>>> futureTaskList = new ArrayList<>();

1.最内层 就是我们通过processOneThread方法把List类型转换为List类型
2.第二层就是调用分批次处理方法把我们的数据切分成5个为一个单位的批次,例如这里是200个切分成20次,即对应的

FutureTask<List<String>> futureTask = new FutureTask<>(callable);

用futureTast接收,FutureTask是一个包装器,它通过接受Callable来创建,它同时实现了Future和Runnable接口,由FutureTask创建一个Thread对象。
3. 每一个批次就启动一个线程去处理

 new Thread(futureTask).start();
  1. 再把处理把每一个批次的list丢进我们进行收集的futureTaskList也就是最外层的list中
  futureTaskList.add(futureTask);

这里说到底还是用单线程去处理整个的问题,只是分批次了,即并行的思想
在这里插入图片描述

如何获取返回的数据

  // 获取线程返回的数据
        for (FutureTask futureTask : futureTaskList) {
            List<String> processData = (List<String>) futureTask.get();
            output.addAll(processData);
        }

很明显的是通过futureTask.get()方法去获取我们要返回的数据

但是ctrl+鼠标左键点进这个方法会发现实现的是我们futureTast下的get方法
在这里插入图片描述
1.先查看当前线程的状态值
2.对状态值进行判定,是否创建线程
3.如果状态值是就绪态以上就进入awaitDown方法
状态值:
在这里插入图片描述

awaitDown方法
在这里插入图片描述
在这里插入图片描述

第三步替换,用线程池去处理

 public static List<String> processByPool(Integer batchSize) throws ExecutionException, InterruptedException {
        List<String> output = new ArrayList<>();
        List<List<Integer>> batchProcessData = getProcessData(batchSize);

        // 1. 使用线程池
        ExecutorService executorService = new ThreadPoolExecutor(3, 5, 60,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<Runnable>(10), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());

        // 2. 创建执行任务
        List<Future<List<String>>> futureList = new ArrayList<>();
        for (List<Integer> processData : batchProcessData) {
            Callable<List<String>> callable = () -> processOneThread(processData);
            futureList.add(executorService.submit(callable));
        }

        for (Future futureTask : futureList) {
            List<String> processData = (List<String>) futureTask.get();
            output.addAll(processData);
        }
        return output;
    }

不同之处:

  ExecutorService executorService = new ThreadPoolExecutor(3, 5, 60,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<Runnable>(10), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());

        // 2. 创建执行任务
        List<Future<List<String>>> futureList = new ArrayList<>();
        for (List<Integer> processData : batchProcessData) {
            Callable<List<String>> callable = () -> processOneThread(processData);
            futureList.add(executorService.submit(callable));
        }
  List<Future<List<String>>> futureList = new ArrayList<>();
   for (List<Integer> processData : batchProcessData) {
            Callable<List<String>> callable = () -> processOneThread(processData);
            FutureTask<List<String>> futureTask = new FutureTask<>(callable);
            new Thread(futureTask).start();
            // 启动线程
            futureTaskList.add(futureTask);
        }
  1. 第一个不同就是线程池开始的时候会构造一个线程池,丢入一些核心参数
  2. 第二个不同就是在把每个线程执行的结果futureTask通过内部的方法丢入我们的futureList收集中
futureList.add(executorService.submit(callable));

我们点进这个submit方法会发现进入了execytorService这个接口,但是实际的方法肯定是ThreadPoolExecutor这个实现类下的,所以我们就进入这个实现类找submit方法
在这里插入图片描述

最终在ThreadPoolExecutor的父类AbstractExecutorService中找到了这个submit方法
在这里插入图片描述

在这里插入图片描述
这个submit方法最终就是要把我们传入的Callable返回,即内部处理了我们多线程处理方法的

FutureTask<List<String>> futureTask = new FutureTask<>(callable);

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/198058.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习笔记:神经网络的学习(2)

本章上一篇可见链接 https://blog.csdn.net/Raine_Yang/article/details/128682091?spm1001.2014.3001.5501 梯度下降法&#xff08;gradient descend&#xff09; 神经网络学习的目标是找到使损失函数最小的参数&#xff08;权重和偏置&#xff09;。通过求得损失函数&#…

【JavaEE】快速了解什么是Maven?

✨哈喽&#xff0c;大家好&#xff0c;我是辰柒&#xff01;✨ &#x1f6f0;️&#x1f6f0;️系列专栏:【JavaEE】 ✈️✈️本篇内容:学习如何使用maven&#xff01; &#x1f680;&#x1f680;代码存放仓库github&#xff1a;JavaEE代码&#xff01; ⛵⛵作者简介&#xff…

C++STL——stack与queue

stack与queuestack与queuepriority_queue容器适配器vector与list的反向迭代器模拟实现仿函数deque(了解)stack与queue模拟实现priority_queue模拟实现stack与queue 这两个就是之前数据结构学过的栈和队列&#xff0c;只不过多了几个接口。 stack&#xff1a; queue&#xff…

【MySQL】MySQL 8 的 JSON 新特性详解(1)JSON 数据类型

目录一、概述二、MySQL 8 的环境搭建三、创建数据库、数据表并插入默认数据四、JSON格式数据的增加和查询1. 增加一条带JOSN格式的数据2.查询JSON内数据3.带筛选条件的查询五、总结一、概述 你好&#xff0c;我是小雨青年&#xff0c;一名使用MySQL 8 的程序员。 MySQL 8 引入…

Hadoop安装(二) --- Hadoop安装

目录 Hadoop安装&#xff08;一&#xff09;---JDK安装 修改hadoop313的权限 更改配置文件 配置core-site.xml 配置hadoop-env.sh 配置hdfs-site.xml 配置mapred-site.xml 配置yarn-site.xml 配置环境 刷新当前的shell环境 初始化 启动所有 SH 修改hadoop31…

Android Studio 从安装到第一个Android 应用Demo

安装Android Studio 安装需要 上网 &#xff0c;我这挺顺利的&#xff0c;就是在官网下载安装包&#xff0c;一路 Next&#xff0c;大概连下载总共半个小时。 第一个应用 参考官方教程&#xff1a;https://developer.android.com/codelabs/basic-android-kotlin-compose-firs…

Redis最佳实践

一、Redis键值设计 1.1、优雅的key结构 Redis的key&#xff0c;最佳实践约定&#xff1a; 遵循基本格式&#xff1a;【业务名称】:【数据名】:【id】长度不超过44字节不包含特殊字符 好处 可读性强避免key冲突方便管理更节省内存 1.2、拒绝BigKey BigKey通常以Key的大小和…

SOLIDWORKS PDM的智能报表自动生成工具

一、SOLIDWORKS企业高级报表软件介绍&#xff1a; SolidKits.Reports&#xff08;企业高级报表&#xff09;是一款无缝集成于SOLIDWORKS PDM的智能报表自动生成工具&#xff0c;可以自动生成企业所需的各类报表数据&#xff0c;涵盖结构数据报表、离散数据报表、变更数据报表、…

rocketmq源码-consumer负载均衡逻辑

前言 这篇笔记主要记录consumer在启动过程中&#xff0c;负载均衡的逻辑&#xff0c;多个消费者组成一个消费者组&#xff0c;对于集群模式&#xff0c;同一个消费者组中的多个消费者共同消费一个topic下的所有消息&#xff0c;所以每个consumer可能会处理N个messageQueue&…

【4】KVM管理 | 虚拟机的管理 | 克隆 | 快照

目录 1、虚机基本管理 2、虚机的克隆 3、增量镜像 4、虚机快照 1、虚机基本管理 查看正在运行的虚机 [rootlocalhost ~]# virsh list Id Name State ----------------------------------------------------查看所有的虚机 [rootlocalhost ~…

Apache Oozie(1):Apache Oozie简介

1 Oozie 概述 Oozie 是一个用来管理 Hadoop 生态圈 job 的工作流调度系统。由Cloudera 公司贡献给 Apache。Oozie 是运行于 Java servlet 容器上的一个 java web 应用。Oozie 的目的是按照 DAG&#xff08;有向无环图&#xff09;调度一系列的 Map/Reduce或者Hive 等任务。Ooz…

Java SE 进阶(二)之 HashSet底层原理

文章目录前言HashSet底层原理1.哈希表2.哈希值3.底层原理4.回答三个问题前言 关于Set和HashSet的API使用可参见 集合基础入门&#xff08;Collection&#xff0c;ArrayList&#xff0c;HashSet&#xff0c;HashMap&#xff09; HashSet底层原理 1.哈希表 HashSet集合底层采…

Vue组件 —— 单文件组件

追溯vue组件问题 在未讲项目之前&#xff0c;在 这一篇内容当中就讲到了组件引入使用&#xff0c;有内置的组件和动态组件以及封装一个swiper组件&#xff0c;组件也分为全局组件和局部组件&#xff0c;在讲在项目当中去使用组件之前先简单的回顾一下组件的编写&#xff1a; &…

89.【SpringBoot-02】

SpringBoot聊一聊如何构建一个网站(十四)、.SpringBoot整合数据库操作1.整合JDBC(1).SpringData简介(2).整合JDBC(3).JdbcTemplate ⭐2. 整合Druid数据源 &#xff08;德鲁伊&#xff09;(1).Druid简介(2).配置数据源(3).配置Druid数据源监控(4).配置Druid数据源过滤器(5).注解…

Echarts的Y轴添加定值横线的示例

第010个点击查看专栏目录Echarts折线图的y轴要画一条横线&#xff0c;主要是在series中设置markLine的图表标线参数&#xff0c;具体的参考源代码。文章目录示例效果示例源代码&#xff08;共142行&#xff09;相关资料参考专栏介绍示例效果 示例源代码&#xff08;共142行&…

怎么在Windows电脑更新 DirectX ?

玩游戏的人应该都对DirectX不陌生&#xff0c;它可以提高游戏或多媒体程序的运行效率&#xff0c;增强3d图形和声音效果。但很多人都不知道DirectX该如何更新&#xff0c;这篇文章将以Win10为例&#xff0c;教大家怎么在电脑上更新DirectX。 一、检查当前DirectX版本 如果你不…

简单聊一聊组件封装

封装一个思维导图组件 最近封装了一个简单的思维导图组件&#xff0c;在此简单记录一下心里历程 组件样式 组件结构设计 节点之间的线分成三部分&#xff0c;分别是竖线左边的横线A、竖线B、竖线右边的横线C&#xff0c;所以一个节点可以包含以下几个元素&#xff1a; 横线…

VBA提高篇_18 VBA代码录制优化Select(tion)及表格合并Merge(cells()/Rows()/Columns()

文章目录1. Cells(1,1)2. Rows(Str)和Columns(Str)3. VBA合并单元格3.1 Range.MergeCells属性:3.2 Range.Merge/UnMerage属性:3.3 Range.Merge(参数True/False)3.4 操作合并/取消合并单元格的两种方法4. Select / Selection 和 录制宏的代码优化4.1 Select / Selection4.2 录制…

anconda的pip下载包出现的问题

问题一: 在anconda里面如何创建新的python环境(也就是更换新的python版本) 1.先打开anconda软件,创建需要的环境 2. 环境创建好之后,去pycharm里面进行配置解释器 3. 这样就可以用了 问题二:pip的安装软件时出现包找不到的问题? 注意:因为我们刚刚创建了一个python环境,等…

Python基于已知的分幅条带号筛选出对应遥感影像文件的方法

本文介绍基于Python语言&#xff0c;结合已知研究区域中所覆盖的全部遥感影像的分幅条带号&#xff0c;从大量的遥感影像文件中筛选落在这一研究区域中的遥感影像文件的方法。 首先&#xff0c;先来明确一下本文所需实现的需求。现已知一个研究区域&#xff08;四川省&#xff…