Java并行流:一次解决多线程编程难题,让你的程序飞起来

news2025/1/20 10:59:12

前言

  在日常的工作中,为了提高程序的处理速度,充分利用多核处理器的性能,我们需要手动编写多线程代码。但是多线程编程非常复杂,容易出现死锁、竞态条件等问题,给我们带来了很大的困扰。而 Java 并行流则提供了一种更加简单、易用、安全的并发编程方式,可以让我们更加轻松地编写高效的并发程序。

使用多线程下载文件

public class MultiThreadExample {

    public static void main(String[] args) throws InterruptedException {

        List<String> urls = Arrays.asList(
            "https://example.com/file1.txt",
            "https://example.com/file2.txt",
            "https://example.com/file3.txt",
            "https://example.com/file4.txt",
            "https://example.com/file5.txt"
        );
        
        int threads = 5;
        int chunkSize = urls.size() / threads;
        int startIndex = 0;
        int endIndex = chunkSize;

        // 创建线程列表
        List<DownloadThread> downloadThreads = new ArrayList<>();

        // 启动多个线程进行文件下载
        for (int i = 0; i < threads; i++) {
            downloadThreads.add(new DownloadThread(urls, startIndex, endIndex));
            downloadThreads.get(i).start();
            startIndex += chunkSize;
            endIndex += chunkSize;
        }

        // 等待所有线程结束并汇总结果
        for (DownloadThread downloadThread : downloadThreads) {
            downloadThread.join();
        }

        System.out.println("文件下载完成");
    }
}

class DownloadThread extends Thread {
    private List<String> urls;
    private int start;
    private int end;

    public DownloadThread(List<String> urls, int start, int end) {
        this.urls = urls;
        this.start = start;
        this.end = end;
    }

    @Override
    public void run() {
        for (int i = start; i < end; i++) {
            HttpUtil.download(urls.get(i));
        }
    }
}

  我们首先将要下载的文件 URL 存储在一个 List 中,然后为每个块创建了一个 DownloadThread 对象,并启动了多个线程进行下载操作。每个线程只负责处理 URL 的一个块,调用 HttpUtil.download 方法进行文件下载操作。最后,我们等待所有线程结束即可。

使用Fork/Join进行下载

  import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;

public class ForkJoinExample {

    public static void main(String[] args) {
        List<String> urls = Arrays.asList(
            "https://example.com/file1.txt", 
            "https://example.com/file2.txt", 
            "https://example.com/file3.txt", 
            "https://example.com/file4.txt", 
            "https://example.com/file5.txt"
        );
        ForkJoinPool pool = new ForkJoinPool();
        pool.invoke(new DownloadAction(urls, 0, urls.size()));
        System.out.println("文件下载完成");
    }

    static class DownloadAction extends RecursiveAction {
        private List<String> urls;
        private int start;
        private int end;

        public DownloadAction(List<String> urls, int start, int end) {
            this.urls = urls;
            this.start = start;
            this.end = end;
        }

        @Override
        protected void compute() {
            if (end - start <= 1) {
                HttpUtil.download(urls.get(start));
                return;
            }

            int mid = (start + end) / 2;
            DownloadAction leftAction = new DownloadAction(urls, start, mid);
            DownloadAction rightAction = new DownloadAction(urls, mid, end);
            invokeAll(leftAction, rightAction);
        }
    }
}

  在这个示例中,我们使用了 ForkJoin 框架来实现文件下载。首先,我们创建了一个 DownloadAction 类,继承自 RecursiveAction 类,表示一个递归操作。在 compute 方法中,我们首先判断当前操作的 URL 是否为一个,如果是,则直接调用 HttpUtil.download 方法进行文件下载。如果不是,则将 URL 列表分为两半,分别创建两个子任务进行处理,然后使用 invokeAll 方法将这两个子任务提交到线程池中并等待它们完成。

  在 main 方法中,我们首先创建了一个 ForkJoinPool 对象,然后调用 invoke 方法来执行 DownloadAction 操作。在这里,我们使用了默认的线程池,也可以根据需要创建自定义的线程池。

使用Java并行流

import java.util.Arrays;
import java.util.List;

public class ParallelStreamExample {

    public static void main(String[] args) {
        List<String> urls = Arrays.asList(
            "https://example.com/file1.txt", 
            "https://example.com/file2.txt", 
            "https://example.com/file3.txt", 
            "https://example.com/file4.txt", 
            "https://example.com/file5.txt"
        );
        urls.parallelStream().forEach(url -> HttpUtil.download(url));
        System.out.println("文件下载完成");
    }
}

  在这个示例中,我们使用了 Java 并行流来实现文件下载。首先,我们创建了一个 URL 列表,然后使用 parallelStream 方法将其转换为并行流。接着,我们使用 forEach 方法遍历并行流中的每个 URL,并使用 HttpUtil.download 方法进行文件下载。在这个过程中,Java 会自动将并行流中的元素分配给多个线程并行执行,以提高程序的性能。

Java 并行流是什么?

  好了,相信看了上面的案例,应该对并行流有了一个简单的认识了吧。让原本又丑又长的代码,一下就变得眉清目秀了。所以那让我们进一步的来了解它吧。

  Java 并行流是 Java 8 中新增的一个特性,它提供了一种便捷的方式来进行并发计算。在传统的 Java 编程中,为了利用多核处理器的性能,我们需要手动编写多线程代码。但是多线程编程非常复杂,容易出现死锁、竞态条件等问题,给我们带来了很大的困扰。而 Java 并行流则提供了一种更加简单、易用、安全的并发编程方式,可以让我们更加轻松地编写高效的并发程序。

  Java 并行流的核心是将数据集合分成多个小块,然后在多个处理器上并行处理,最后将结果合并成一个结果集。使用 Java 并行流可以有效地利用多核处理器的性能,提升程序运行效率。此外,Java 并行流还提供了一系列的中间操作和终止操作,可以方便地进行数据筛选、映射、过滤等操作。

Java并行流的实现原理?

  Java 并行流是基于 Fork/Join 框架实现的,它使用了多线程来处理流操作。具体来说,Java 并行流的实现原理如下:

  1. 拆分数据

  当并行流操作开始时,数据会被拆分成多个小块。每个小块都会被分配给不同的线程去处理。

  1. 执行任务

  每个线程会独立地执行任务。线程会使用 fork/join 框架将自己的任务拆分成更小的子任务,并将这些子任务分配给其他线程。

  1. 合并结果

  当所有线程完成任务后,它们会将自己的结果合并到一起。这个过程类似于 reduce 操作,不同之处在于它是并行的。

  Java 并行流的是基于 Fork/Join 框架实现的,而Fork/Join 框架是 Java 7 引入的一个用于并行计算的框架,它基于工作窃取算法,可以将一个大任务拆分成多个小任务,每个线程独立地处理一个小任务。在 Java 8 中,通过对 Stream 接口的扩展,使得并行计算更加容易实现。

  需要注意的是,Java 并行流在执行操作时,会根据当前计算机的 CPU 核心数来确定并行线程的数量,如果并行线程数量过多,会造成过多的上下文切换,反而会降低程序的性能。因此,在使用并行流时需要注意控制并行线程的数量。

三种方式对比

   在文件下载这个例子中,我们使用了多线程、ForkJoin 框架和 Java 并行流三种方式来实现。我们来对比一下这三种方式的优缺点。

1. 多线程方式

优点:

  • 可以手动控制线程的数量,适用于对线程数量有特殊要求的场景。
  • 可以使用线程池来重用线程,减少线程创建和销毁的开销。
  • 可以使用 waitnotify 等机制来实现线程间的通信和协作。

缺点:

  • 需要手动编写线程的创建和销毁代码,代码复杂度较高。
  • 线程之间的协作和通信需要手动实现,容易出现死锁等问题。
  • 代码的可读性和可维护性较差。

2. ForkJoin 框架方式

优点:

  • 可以自动地将任务拆分成更小的子任务,并将子任务分配给多个线程并行执行,简化了代码实现。
  • 可以通过调整并行度来优化性能,提高代码的灵活性。
  • 可以使用默认的线程池或自定义的线程池来管理线程。

缺点:

  • 不适用于 IO 密集型操作,仅适用于 CPU 密集型操作。
  • 线程之间的协作和通信需要手动实现,容易出现死锁等问题。

3. Java 并行流方式

优点:

  • 可以使用函数式编程的方式简化代码实现,代码可读性较高。
  • 可以自动地将数据分配给多个线程并行处理,简化了代码实现。
  • 可以根据需要选择并行度来优化性能。
  • 可以通过流水线方式优化代码性能,提高代码的灵活性。

缺点:

  • 不适用于 IO 密集型操作,仅适用于 CPU 密集型操作。
  • 对于一些特殊的操作,例如排序和去重,可能需要手动调整代码才能使用并行流。

总结

  Java并行流可以让多线程编程变得更加简单易懂,减少编程中的并发问题,提高代码质量和可维护性。帮助开发人员更加轻松地实现任务并行,充分利用多核处理器的性能,加快程序的执行速度。但是虽然并行流有诸多优点,但是还需要根据具体场景来选择合适的方式。如果是 IO 密集型操作,我们应该使用多线程或者 Java NIO 等技术来实现;如果是 CPU 密集型操作,我们可以使用 ForkJoin 框架或者 Java 并行流来实现。

结尾

  如果觉得对你有帮助,可以多多评论,多多点赞哦,也可以到我的主页看看,说不定有你喜欢的文章,也可以随手点个关注哦,谢谢。

  我是不一样的科技宅,每天进步一点点,体验不一样的生活。我们下期见!

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

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

相关文章

python机器学习和深度学习在气象中的应用

查看原文>>> Python人工智能在气象中的实践技术应用 Python 是功能强大、免费、开源&#xff0c;实现面向对象的编程语言&#xff0c;在数据处理、科学计算、数学建模、数据挖掘和数据可视化方面具备优异的性能&#xff0c;这些优势使得 Python 在气象、海洋、地理、…

14:24面试,14:32就出来了 ,问的实在是太...

从外包出来&#xff0c;没想到算法死在另一家厂子&#xff0c;自从加入这家公司&#xff0c;每天都在加班&#xff0c;钱倒是给的不少&#xff0c;所以也就忍了。没想到8月一纸通知&#xff0c;所有人不许加班&#xff0c;薪资直降30%&#xff0c;顿时有吃不起饭的赶脚。 好在有…

PythonFlash+MySQL实现简单管理系统的增删改查

今天简单分享一下用Python的flash框架结合MySQL来实现信息管理系统的增删改查&#xff01; ps&#xff1a;该博客只完成了信息的添加和查看&#xff0c;删除和修改按照该方法下推即可&#xff01; 实现功能之前我们先在数据库里设置数据&#xff0c;例如&#xff1a; 我们创…

日常记录:天梯赛练习集L1-046 整除光棍

题目&#xff1a; 这里所谓的“光棍”&#xff0c;并不是指单身汪啦~ 说的是全部由1组成的数字&#xff0c;比如1、11、111、1111等。传说任何一个光棍都能被一个不以5结尾的奇数整除。比如&#xff0c;111111就可以被13整除。 现在&#xff0c;你的程序要读入一个整数x&#x…

Mac环境下nvm的安装与环境配置

目录 1.nvm简介 2.nvm安装 3.配置nvm环境 1.nvm简介 nvm全称 Node Version Manager &#xff0c;意思为node版本控制&#xff1b;它是一个命令行应用&#xff0c;可以快速地更新、安装、使用、卸载本机的全局 node.js 版本。他可以在同一台电脑上进行多个node版本之间的切换…

redis基础(6.0)数据结构、事务、常用组件等

1 概述 1.1 redis介绍 Redis 是互联网技术领域使用最为广泛的存储中间件&#xff0c;它是「Remote Dictionary Service」的首字母缩写&#xff0c;也就是「远程字典服务」。Redis 以其超高的性能、完美的文档、 简洁易懂的源码和丰富的客户端库支持在开源中间件领域广受好评。…

华为手表开发:WATCH 3 Pro(16)传感器订阅气压

华为手表开发&#xff1a;WATCH 3 Pro&#xff08;16&#xff09;传感器订阅气压初环境与设备气压传感器介绍与说明鸿蒙开发文件夹&#xff1a;文件新增展示的文本标记index.hmlindex.cssindex.js初 希望能写一些简单的教程和案例分享给需要的人 鸿蒙可穿戴开发 环境与设备 …

【目标检测】YOLOv5:修改自己的网络结构

前言 YOLOv5就像一座金矿&#xff0c;里面有无数可以学习的东西。之前的博文一直将YOLOv5当作一个黑盒使用&#xff0c;只考虑模型的输入和输出&#xff0c;以此来对模型进行二次开发。 本篇博文将更近一层&#xff0c;深入到“金矿”内部&#xff0c;来尝试对模型结构进行替换…

高并发浅析

什么是高并发 高并发指通过设计保证系统能够同时并行处理很多请求&#xff0c;是分布式系统非常重要的概念 评价分布式系统性能的指标有&#xff1a; 响应时间&#xff1a;系统对请求做出响应的时间。吞吐量&#xff1a;单位时间内处理的请求数量。QPS&#xff08;和吞吐量基…

C++标准库 -- 顺序容器 (Primer C++ 第五版 · 阅读笔记)

C标准库 -- 顺序容器(Primer C 第五版 阅读笔记&#xff09;第9章 顺序容器------(持续更新)9.1、顺序容器概述9.2、容器库概览9.2.1 、迭代器9.2.2 、容器类型成员9.2.3 、begin 和 end 成员9.2.4 、容器定义和初始化9.2.5 、赋值和 swap9.2.6 、容器大小操作9.2.7 、关系运算…

电脑0x0000001A蓝屏错误怎么U盘重装系统教学

电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug&#xff0c;只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢&#xff1f;来看看以下的详细操作方法教学吧。 准备工作&…

ThinkPad-L480电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。&#xff08;下载请直接百度黑果魏叔&#xff09; 硬件型号驱动情况 主板ThinkPad-L480 处理器Intel Core i7-8550U已驱动 内存16GB DDR4 2400Mhz已驱动 硬盘Intel 760p 512GB已驱动 显卡Intel UHD 620已驱动 声卡瑞昱…

【探花交友】day06—即时通信

目录 1、即时通信 1.1、什么是即时通信&#xff1f;​编辑 1.2、功能说明 1.3、技术方案 2、环信 2.1、开发简介 2.2、环信Console 2.3、接口说明 3、抽取环信组件 3.1、编写HuanXinTemplate 3.2、编写Properties对象 3.3、配置 3.4、测试 4、用户体系集成 4.1、…

力扣刷题第一天:剑指 Offer 18. 删除链表的节点、LC206.反转链表

目录 零、前言 剑指 Offer 18. 删除链表的节点 一、题目描述 二、解题思路 三、完整代码 LC206.反转链表 一、题目描述 二、解题思路 三、完整代码 零、前言 这篇文章主要讲解两道链表相关的题目&#xff0c;分别是剑指 Offer 18和LC206。链表作为数据结构中重要的一…

Vue学习——【第五弹】

前言 上一篇文章 Vue学习——【第四弹】 中学到了数据代理&#xff0c;这篇文章接着学习 Vue中的事件处理。 事件处理 我们在学习JavaScript时就经常接触事件处理&#xff0c;比如在进行表单、按钮、列表折叠等操作时&#xff0c;我们就经常用到 click&#xff08;点击&…

Redis源码之Hash表实现

通常我们如果要设计一个 Hash 表&#xff0c;那么我们需要考虑这几个问题&#xff1a; 有没有并发操作Hash冲突如何解决以什么样的方式扩容对 Redis 来说&#xff0c;首先它是单线程的工作模式&#xff0c;所以不需要考虑并发问题。 想实现一个性能优异的 Hash 表&#xff0c…

ubuntu快速安装VMware Tools(全屏用的)

VMware Tools实现主机和虚拟机的文件共享。 第一步 打开VMware Workstation,启动ubuntu系统。 点击主界面的&#xff08;虚拟机&#xff09;——点击&#xff08;安装VMware Tools&#xff09;。 弹出提示框点击是——等待自动下载完成。 第二步 将安装包复制到桌面&#x…

ESP32 web WiFi 管理器esp32-wifi-manager

拓 2023/04/09-2022/04/11 1. 简介 github仓库 https://github.com/tonyp7/esp32-wifi-manager 说明 esp32-wifi-manager是esp32的纯C esp-idf组件&#xff0c;可通过门户网站轻松管理wifi网络。 esp32-wifi-manager是一个集所有功能于一身的wifi扫描仪、http服务器和dns守…

2022年第十三届蓝桥杯题解(全)C/C++

A题就是一个简单的进制转化&#xff0c;代码实现如下&#xff1a; #include <bits/stdc.h>using namespace std;const int N 1e5 10;int main() {int x 2022;int a 1;int res 0;while(x) {res (x % 10) * a;a a * 9;x / 10;}cout << res;return 0; } B题有…

【论文阅读笔记】COFFEE: A Contrastive Oracle-Free Framework for Event Extraction

论文题目&#xff1a;COFFEE: A Contrastive Oracle-Free Framework for Event Extraction 论文来源&#xff1a; 论文链接&#xff1a;https://arxiv.org/pdf/2303.14452.pdf 代码链接&#xff1a; 0 摘要 事件抽取是一项复杂的信息抽取任务&#xff0c;它涉及到从非结构…