【Java多线程批量数据导入的方法】

2023-11-20

前言:

当遇到大量数据导入时,为了提高处理的速度,可以选择使用多线程来批量处理这些处理。常见的场景有:

  • 大文件导入数据库(这个文件不一定是标准的CSV可导入文件或者需要在内存中经过一定的处理)
  • 数据同步(从第三方接口拉取数据处理后写入自己的数据库)

以上的场景有一个共性,这类数据导入的场景简单来说就是将数据从一个数据源移动到另外一个数据源,而其中必定可以分为两步

  • 数据读取:从数据源读取数据到内存
  • 数据写入:将内存中的数据写入到另外一个数据源,可能存在数据处理

而且根据读取的速度一般会比数据写入的速度快很多,即读取快,写入慢。

设计思路

由于场景的特点是读取快,写入慢,如果是使用多线程处理,建议是数据写入部分改造为多线程。而数据读取可以改造成批量读取数据。简单来说就是两个要点:

  • 批量读取数据
  • 多线程写入数据

示例

多线程批量处理最简单的方案是使用线程池来进行处理,下面会通过一个模拟批量读取和写入的服务,以及对这个服务的多线程写入调用作为示例,展示如何多线程批量数据导入

  1. 模拟服务
import java.util.concurrent.atomic.AtomicLong;
/**
* 数据批量写入用的模拟服务
*
* @author RJH
* create at 2019-04-01
*/
public class MockService {
/**
* 可读取总数
*/
private long canReadTotal;
/**
* 写入总数
*/
private AtomicLong writeTotal=new AtomicLong(0);
/**
* 写入休眠时间(单位:毫秒)
*/
private final long sleepTime;
/**
* 构造方法
*
* @param canReadTotal
* @param sleepTime
*/
public MockService(long canReadTotal, long sleepTime) {
this.canReadTotal = canReadTotal;
this.sleepTime = sleepTime;
}
/**
* 批量读取数据接口
*
* @param num
* @return
*/
public synchronized long readData(int num) {
long readNum;
if (canReadTotal >= num) {
canReadTotal -= num;
readNum = num;
} else {
readNum = canReadTotal;
canReadTotal = 0;
}
//System.out.println("read data size:" + readNum);
return readNum;
}
/**
* 写入数据接口
*/
public void writeData() {
try {
// 休眠一定时间模拟写入速度慢
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 写入总数自增
System.out.println("thread:" + Thread.currentThread() + " write data:" + writeTotal.incrementAndGet());
}
/**
* 获取写入的总数
*
* @return
*/
public long getWriteTotal() {
return writeTotal.get();
}
}

  1. 批量数据处理器
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 基于线程池的多线程批量写入处理器
* @author RJH
* create at 2019-04-01
*/
public class SimpleBatchHandler {
private ExecutorService executorService;
private MockService service;
/**
* 每次批量读取的数据量
*/
private int batch;
/**
* 线程个数
*/
private int threadNum;
public SimpleBatchHandler(MockService service, int batch,int threadNum) {
this.service = service;
this.batch = batch;
//使用固定数目的线程池
this.executorService = Executors.newFixedThreadPool(threadNum);
}
/**
* 开始处理
*/
public void startHandle() {
// 开始处理的时间
long startTime = System.currentTimeMillis();
System.out.println("start handle time:" + startTime);
long readData;
while ((readData = service.readData(batch)) != 0) {// 批量读取数据,知道读取不到数据才停止
for (long i = 0; i < readData; i++) {
executorService.execute(() -> service.writeData());
}
}
// 关闭线程池
executorService.shutdown();
while (!executorService.isTerminated()) {//等待线程池中的线程执行完
}
// 结束时间
long endTime = System.currentTimeMillis();
System.out.println("end handle time:" + endTime);
// 总耗时
System.out.println("total handle time:" + (endTime - startTime) + "ms");
// 写入总数
System.out.println("total write num:" + service.getWriteTotal());
}
}
  1. 测试类
/**
* SimpleBatchHandler的测试类
*/
public class SimpleBatchHandlerTest {
public static void main(String[] args) {
// 总数
long total=100000;
// 休眠时间
long sleepTime=100;
// 每次拉取的数量
int batch=100;
// 线程个数
int threadNum=16;
MockService mockService=new MockService(total,sleepTime);
SimpleBatchHandler handler=new SimpleBatchHandler(mockService,batch,threadNum);
handler.startHandle();
}
}
  1. 运行结果
start handle time:1554298681755
thread:Thread[pool-1-thread-2,5,main] write data:1
thread:Thread[pool-1-thread-1,5,main] write data:2
...省略部分输出
thread:Thread[pool-1-thread-4,5,main] write data:100000
end handle time:1554299330202
total handle time:648447ms
total write num:100000
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Java多线程批量数据导入的方法】 的相关文章

  • 声纳违规:安全性 - 使用 byte[] 时直接存储数组

    我确实遇到过以下两篇关于类似问题的帖子声纳违规 https stackoverflow com questions 11580948 sonar violation security array is stored directly and
  • 使用比较器对对象进行排序给出空指针

    我正在尝试对包含 3 张卡的 ArrayList 进行排序 我正在用比较器来做这件事 这是否太过分了 Card getRank 返回 2 到 14 之间的整数 我完全不知道哪里出了问题 我之前已经成功完成了这个 并与我的其他代码进行了比较
  • Hibernate 自定义架构创建

  • 如何在流中收集到TreeMap中?

    我有两个Collectors groupingBy在流中 我需要收集所有信息TreeMap 我的代码 Map
  • java.sql.SQLException: ORA-01005: 给定的密码为空;登录被拒绝

    我在尝试连接到数据库时遇到以下异常 java sql SQLException ORA 01005 null password given logon denied at oracle jdbc driver T4CTTIoer proce
  • 使用 Gson 序列化时如何公开类名

    我的场景非常复杂 但总结如下 我试图了解编译器的源代码 并了解每个 AST 节点代表什么 我正在生成不同程序的 AST 的 JSON 序列化 然后检查可视化的 JSON 输出 它工作得很好 除了一个问题是在 Gson 中生成的 JSON 数
  • 按对象值分组,统计后按最大对象属性设置组键

    我设法使用 Java 8 Streams API 编写了一个解决方案 该解决方案首先按对象 Route 的值对列表进行分组 然后计算每组中的对象数量 它返回一个映射 Route gt Long 这是代码 Map
  • Selenium - 保存网站,包括所有图像、css、dom

    我想使用 firefox 或 chrome 访问带有 selenium 的页面 当页面加载时 我想从页面下载所有图像 css dom 我想存储每张图像 就像我在其中找到它们一样 chrome gt Tools gt Development
  • (Java) 在 Mac OS X 上以编程方式访问“系统根目录”下的 SSL 证书

    我正在编写一个 Java 应用程序 它可以通过远程 Https 站点进行 REST Api 调用 远程站点由受信任的证书签名 它在 Windows 上运行良好 但由于 SSL 证书问题 在 OS X 上运行时遇到问题 我做了一些挖掘 发现原
  • 将 emoji 替换为适当的 java 代码

    我正在开发一个简单的java程序 它可以接受这样的字符串 停止 你违反了 法律 但是现在 你 并将每个表情符号替换为适当的 java 字符 我不知道该怎么称呼他们 这是一个例子 汽车表情符号 将替换为 uD83D uDE97 这允许我有一个
  • Java - 同步方法导致程序大幅减慢

    我正在尝试了解线程和同步 我做了这个测试程序 public class Test static List
  • Java 泛型和数字类型

    我想创建一个通用方法来有效地执行此操作 class MyClass static
  • 如何使用 UUID 生成唯一的正 Long

    我需要为我的数据库主键列生成唯一的长 ID 我以为我可以用UUID randomUUID getMostSignificantBits 但有时它也会产生一些负多头 这对我来说是个问题 是否可以从 UUID 中仅生成正长 将会有数十亿个条目
  • 在 Java 中打开现有文件并关闭它。

    是否可以在java中打开一个文件附加数据并关闭多次 例如 psuedocode class variable declaration FileWriter writer1 new FileWriter filename fn1 writer
  • 如何获取队列中的第 n 个项目?

    我的应用程序中有许多队列和优先级队列 我想轻松访问这些队列中的第 n 个项目 但没有看到使用 API 实现此目的的简单方法 我想我可以创建一个Iterator并迭代到第 n 个元素或使用toArray index 但似乎应该有一个更简单的方
  • EclipseLink 2.7.0 和 JPA API 2.2.0 - 签名不匹配

    当运行由maven构建的具有以下依赖项的项目时
  • Android - 保持用户登录状态

    我正在尝试使用 PHP 和 MySQLi for Android 进行登录 我不明白的是如何保持用户登录状态 我看到一个简单的教程 其中有人使用 SQLite 来保护信息 但我不知道这是否真的安全 如何保存用户信息以保持用户登录状态 谢谢
  • 线程睡眠阻止我的 Swing 应用程序执行

    我的应用程序发生的事情是有道理的 但我不知道如何修复它 以下是我的应用程序功能的简要描述 计时器窗口应显示在屏幕右下角并显示实时时间 一小时后 它应该执行一些操作 我还没有决定该操作 我面临的问题是定时器 java当我刷新实时计时器的秒数时
  • Android应用程序中的模式输入

    我想知道是否有其他替代方案可以替代 Android 上平庸的 EditText 密码输入 是否有 API 或开源代码可以集成到我的应用程序中 类似于锁屏图案解锁 Intent 可能会返回哈希值 数字 字符串或代表用户输入的模式的任何内容 我
  • javafx中的stackpane和root有什么区别?

    我正在练习javafx做饼图 以下是开发饼图的代码 如果我这样做Group并与StackPane 我发现输出没有区别 我已经评论了组部分 只是徘徊两者之间的区别 import javafx application Application i

随机推荐

  • 微信小程序接入支付功能并实现支付

    随着微信小程序越来越广泛的应用 现在小程序几乎无所不能 绝对啦 哈哈 那么就会有很多微信小程序需要有支付的需求 那么该文章将带领大家走一遍如何实现微信小程序的支付功能 第一步 微信小程序管理后台 gt 微信支付 gt 接入微信支付 及关联
  • 0基础也能看懂,熬夜7天肝出这一份3w字软件测试学习手册【建议收藏】

    随着互联网行业的发展迅速 很多人都想涌进来 近年来软件测试岗位也呈现出了前所未有的火爆趋势 尤其2021年国家实现教育 双减 政策 激起了很多教培从业者 幼师 机械加入软件测试行业学习 剑哥今天抽个时间简单的给大家说下 对于0基础的朋友到底
  • python3图像处理_Python3与OpenCV3.3 图像处理(二)--图像基本操作

    一 本节简述 本节主要讲解图像的一些基础知识 以及图像的加载和获得属性 最后将会学到 OpenCV 摄像头的简单使用 二 图像基本知识 1 图像是什么 图像是客观对象的一种相似性的 生动性的描述或写真 是人类社会活动中最常用的信息载体 或者
  • CST2020 安装包和安装步骤

    安装包和破解码的百度云链接 链接 https pan baidu com s 1RNSWxVxb DIu8dg8gkCzAw 提取码 dve7 如果失效可评论留言 谢谢 1 关闭防火墙和杀毒软件 2 解压后 以管理员模式运行setup文件
  • 使用inet_ntop转换IPv6地址时在macOS和linux上的行为不一样

    下面这段python代码在macOS和linux时运行的结果是不同的 import socket ip socket inet pton socket AF INET6 1 2 3 0 5 6 7 8 print socket inet n
  • ubuntu20.04 apt 安装报 E: Unable to correct problems, you have held broken packages.

    在安装软件的时候报错 root root sudo apt get install vim Reading package lists Done Building dependency tree Reading state informat
  • Leetcode刷题日志5.0

    目录 前言 1 两数相加 2 无重复字符的最长子串 3 整数反转 4 删除链表的倒数第 N 个结点 前言 今天我又来继续分享最近做的题了 现在开始进入我们快乐的刷题时间吧 编程语言Python3 0 难度 中等 1 两数相加 给你两个 非空
  • Redis工具类(缓存操作,Object转换成JSON数据)

    依赖spring data redis 2 4 1 jar Component Data public class RedisUtils Autowired private RedisTemplate
  • 双向链表详解

    目录 一 双向链表的概念及结构 二 双向链表的方法及其实现 2 1 双向链表 2 2 addFirst int data 头插法 2 3 addLast int data 尾插法 2 4 size 链表长度 2 5 display 打印链表
  • Centos6.4 用rpm方式安装MySql5.6

    1 查看系统是否安装了MySQL 使用命令 rpm qa grep mysql 2 卸载已安装的MySQL 卸载mysql命令如下 rpm e nodeps mysql libs 5 1 61 4 el6 x86 64 要将 var lib
  • sql局部变量和全局变量_有效使用SQL内置全局变量

    SQL内置全局变量是只读的 由IBM DB2 for i维护 并且是受信任且易于使用的资源 存在一些全局变量是为了与DB2系列兼容 并且包含在SYSIBM模式中 其他全局变量提供IBM i特定的值 并包含在QSYS2模式中 全局变量使应用程
  • 【实验二】【创建表并输入数据】

    文章目录 目的表 XSQK 学生情况 KC 课程 XS KC 学生 课程 T SQL创建表 1 新建查询 2 切换数据库 3 输入T SQL查询语句创建表 XSQK 学生情况 KC 课程 XS KC 学生 课程 4 执行命令 5 查看表 S
  • JVM笔记5:虚拟机栈

    目录 1 虚拟机主要特点 虚拟机栈出现的背景 初步印象 内存中的栈与堆 虚拟机栈基本内容 2 虚拟机栈的常见异常与如何设置栈大小 3 栈的存储结构和运行原理 栈中存储什么 栈运行原理 4 栈帧的内部结构 每个栈帧中存储着 5 局部变量表 6
  • 基于python的全球疫情数据分析及可视化系统

    源码获取 https www bilibili com video BV1Ne4y1g7dC 现如今 随着互联网的发展 人们获取信息的方式也各有不同 以前的传统方式的信息流与电视 报纸 书籍 信件 等等 因为互联网的使用 现在的互联网媒体已
  • C++ 判断文件是否被打开,防止重复打开

    如何判断文件是否已经被打开 在这里通过文件的一些属性实现判断文件是否被打开 通过QFile将文件尝试实现例如linux的move操作和rm r 的操作 就可以判断是否文件被占用 首先添加 include QFile 头文件 再设置全局的判断
  • 项目中:Json文件的读取

    项目中 Json文件的读取 读Json文件 取Json文件中内容 举例 举例 Json文件内容如下 Flickr8k images sentids 39300 39301 39302 39303 39304 imgid 7860 sente
  • C++11中 std::bind 的两种用法

    概述 std bind的头文件是
  • hadoop环境搭建之关闭防火墙和SELinux

    每一台服务器上都要做1 2 1 关闭防火墙 查看防火墙状态 systemctl status firewalld 关闭防火墙 systemctl disable firewalld systemctl stop firewalld 查看防火
  • iOS 获取系统键盘UIKeyboard方法

    公司项目需求 需要让弹窗显示在键盘所在的图层之上 而不是在弹窗出现的时候消失 如图1 系统弹窗出现的时候会使键盘暂时不显示 而这种效果显然不符合要求的 由于没想到更好的办法 只好从键盘自身的UIKeyboard做文章了 通过获取当前键盘的U
  • 【Java多线程批量数据导入的方法】

    前言 当遇到大量数据导入时 为了提高处理的速度 可以选择使用多线程来批量处理这些处理 常见的场景有 大文件导入数据库 这个文件不一定是标准的CSV可导入文件或者需要在内存中经过一定的处理 数据同步 从第三方接口拉取数据处理后写入自己的数据库