Java多线程数据分片处理

java对于数据量较大的数据插入处理或者业务逻辑调用多个远程接口出现性能瓶颈,如何用多线程优化

示例一、对于插入百万级批量数据的处理

1、基于java jdk并发包的实现数据分片处理

//线程池的定义
    private static final int corePoolSize = Runtime.getRuntime().availableProcessors();
    private static final int maximumPoolSize = corePoolSize * 4 + 1;
    private static final ExecutorService executorService = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
            3L, TimeUnit.HOURS,
            new ArrayBlockingQueue<>(10000), new DefaultThreadFactory("async-data-worker"),
            new ThreadPoolExecutor.CallerRunsPolicy()); //业务数据分片
  List<T> datas= ...获取业务数据,若数据量过大,可以只获取id集分片,然后再查询整个model数据处理
              
  List<List<T>> partitions = Lists.partition(datas, 1000);

   List<CompletableFuture> futures = new ArrayList<>();
                    for (int i = 0; i < partitions.size(); i++) {
                        List<T> pDatas = partitions.get(i);
                        final int j =i;
                    futures.add(CompletableFuture.supplyAsync(() -> saveBatch(pDatas), executorService)                            //不需要处理返回值不需要执行thenAccept方法
                            .thenAccept((s) -> results.add(j)));
                }
//                CompletableFuture.allOf(futures.stream().toArray(CompletableFuture[]::new)).join();//不需要后续处理直接join等待所有子任务执行完成
                CompletableFuture.allOf(futures.stream().toArray(CompletableFuture[]::new)).thenRun(() -> {
                    results.forEach(item->{
                            log.info("批量数据执行结果={}",item);
                    });
                }).get();

从log打印的结果来看,整个返回的结果数据集是无序的

2、基于Google 的Guava的并发包实现数据分片处理

//业务数据分片
                List<T> datas= ...获取业务数据,若数据量过大,可以只获取id集分片,然后再查询整个model数据处理

                List<List<T>> partitions = Lists.partition(datas, 1000);
                // 定义监听执行服务
                ListeningExecutorService listeningExecutorService =
                        MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
                List<ListenableFuture<Integer>> listenableFutures = new ArrayList<>();
                for (int i = 0; i < partitions.size(); i++) {
                    List<T> pDatas= partitions.get(i);
                    final int j =i;
                    listenableFutures.add(listeningExecutorService.submit(()->{
                        saveBatch(pDatas);
                        return j;
                    }));
                }
                ListenableFuture<List<Integer>> listListenableFuture = Futures.allAsList(
                        Lists.newArrayList(listenableFutures));
                List<Integer> lists = listListenableFuture.get();
                lists.forEach(item->{
                    System.out.println(item);
                });

Guava的实现是要简洁一些的,从log打印的结果来看,整个返回的结果数据集是有序的
多接口并行调用用多线程优化也是同理

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用多线程来实现分片下载文件的功能。以下是一个简单的示例代码: ```java import java.io.*; import java.net.HttpURLConnection; import java.net.URL; public class MultiThreadFileDownloader { private static final int BUFFER_SIZE = 4096; private static final int NUM_THREADS = 4; // 设置线程数量 public static void main(String[] args) { String fileUrl = "http://example.com/file.pdf"; // 文件的URL String saveDir = "C:/downloads"; // 下载文件保存的目录 try { URL url = new URL(fileUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); int fileSize = connection.getContentLength(); connection.disconnect(); int partSize = fileSize / NUM_THREADS; // 计算每个线程下载的文件大小 for (int i = 0; i < NUM_THREADS; i++) { int startRange = i * partSize; int endRange = (i + 1) * partSize - 1; if (i == NUM_THREADS - 1) { endRange = fileSize - 1; // 最后一个线程下载剩余的部分 } Thread thread = new DownloadThread(fileUrl, saveDir, startRange, endRange); thread.start(); } } catch (IOException e) { e.printStackTrace(); } } static class DownloadThread extends Thread { private String fileUrl; private String saveDir; private int startRange; private int endRange; public DownloadThread(String fileUrl, String saveDir, int startRange, int endRange) { this.fileUrl = fileUrl; this.saveDir = saveDir; this.startRange = startRange; this.endRange = endRange; } public void run() { try { URL url = new URL(fileUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestProperty("Range", "bytes=" + startRange + "-" + endRange); InputStream inputStream = connection.getInputStream(); String fileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1); FileOutputStream outputStream = new FileOutputStream(saveDir + File.separator + fileName, true); byte[] buffer = new byte[BUFFER_SIZE]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } inputStream.close(); outputStream.close(); System.out.println("线程下载完成:" + startRange + " - " + endRange); } catch (IOException e) { e.printStackTrace(); } } } } ``` 这段代码通过创建多个线程,每个线程负责下载文件的一部分,然后将下载的数据写入本地文件。你可以根据需要调整线程数量和缓冲区大小。记得将 `fileUrl` 替换为你要下载的文件的实际URL,将 `saveDir` 替换为你希望保存下载文件的目录。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值