Java Stream与多线程

news2024/10/5 1:16:57

Java Stream

1. 问题引入

学习了尚硅谷的JUC,周阳老师讲的商城比较价格的案例,自己模拟了一个多线程的demo, 多线程处理任务并且汇总结果,出现了疑问,实例代码放在下面,读者有兴趣的话可ctrl+cv玩一玩

如下是自定义的任务类

public class Task implements Callable<String> {
    private String taskName;
    private Date taskTime;
    // 构造函数,toString那些略去

    //这里是因为前面还弄了线程池处理任务并且汇总结果的,所以实现了Callable接口,
    //这个可以略过不看,因为疑问跟这个无关
    @Override
    public String call() throws Exception {
        try {
            System.out.println("正在处理任务" + this.getTaskName());
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            return this.getTaskName();
        }
    }

}

Main方法

package com.manytask02;


import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;

// 主方法
public class Main {
    public static void main(String[] args) {
        // 1.顺序处理任务
        //testOrder();

        //2.CompletableFuture
        try {
            testCompletable();
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    // 顺序处理任务方法
    public static void testOrder() {
        List<Task> tasks = new ArrayList<>();
        // 创建一系列任务 ( 5个任务)
        for ( int i = 0; i < 5; ++i ) {
            tasks.add(new Task("任务" + i, new Date()));
        }
        // 一 顺序处理
        System.out.println("顺序处理任务开始了~~~~~~~");
        long start = System.currentTimeMillis();
        List<String> strings = takcleByOrder(tasks);
        long end = System.currentTimeMillis();
        System.out.println("顺序处理任务耗时 " + (end-start));

        //返回处理结果
        strings.forEach(System.out::println);
    }
    
    public static List<String> takcleByOrder(List<Task> tasks) {
        List<String> ans = new ArrayList<>();
        for (Task task : tasks) {
            ans.add(takcleTask(task));
        }
        return ans;
    }
    
    //========================================================================
    // CompletableFuture工具
    public static void testCompletable() throws ExecutionException, InterruptedException {
        List<Task> tasks = new ArrayList<>();
        // 创建一系列任务 ( 5个任务)
        for ( int i = 0; i < 5; ++i ) {
            tasks.add(new Task("任务" + i, new Date()));
        }
        // 一 异步处理
        System.out.println("异步处理任务开始了~~~~~~~");
        long start = System.currentTimeMillis();
        List<String> strings = takcleByAsync02(tasks);
        long end = System.currentTimeMillis();
        System.out.println("异步处理任务耗时 " + (end-start));
        //返回处理结果
        strings.forEach(System.out::println);
    }
    
    private static List<String> takcleByAsync02(List<Task> tasks) {
        return  tasks.stream()
                .map(task -> CompletableFuture.supplyAsync(()->takcleTask(task)))
                .collect(Collectors.toList())
                .stream()
                .map(CompletableFuture::join)
                .collect(Collectors.toList());

//        return  tasks.stream()
//                .map(task -> CompletableFuture.supplyAsync(()->takcleTask(task)))
//                .map(CompletableFuture::join)
//                .collect(Collectors.toList());
    }
}

疑问出来了,如下图

在这里插入图片描述

上图中两个红框框中就出现了疑问,第一个红框框中划线的部分,既然前后结果类型一样,为什么不能写成下面的两个map那种形式呢??

从上面主方法(main)代码可以看出,是在比较顺序处理任务和异步处理任务所花费的时间。可是事实却是:写成下面的形式,就不是异步处理任务了,耗时还是5秒。为什么呢,难道是两个map连着一起写有问题吗?

猜想:两个map连着一起写的话,第一个map里面执行了,会紧接着执行另一个map里面的操作,并不是等一个map将流中的所有元素映射完了才执行第二个map里面的映射,由于CompletableFuture的join方法会阻塞,每当第一个map处理任务时,紧接着就执行join了,造成了阻塞,这就相当于是在顺序执行任务了。

public class Mapmap {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 3, 5, 7, 9);
        List<Integer> integers = list.stream()
                .map(i -> {
                    i *= 2;
                    System.out.println(i);
                    return i;
                })
                .map(j -> {
                    j *= 2;
                    System.out.println(j);
                    return j;
                })
                .collect(Collectors.toList());
    }
}

测试一下,如果是像猜想里面的那样的话,输出内容就肯定是2,4,6,12,10,20,14,28,18,36; 如果不是的话那么就是2,6,10,14,18,4,12,20,28,36

在这里插入图片描述

印证了猜想。具体什么原因我也看不懂源码

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

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

相关文章

BEV感知算法的概念

本文来自自动驾驶之心知识星球的国内首个BEV感知全栈系列学习教程 什么是BEV&#xff1f; ----> 上帝视角 Bird’s-Eye-View&#xff0c;鸟瞰图&#xff08;俯视图&#xff09;尺度变化小 &#xff08;离相机远的尺度比较小&#xff0c;离相机近的尺度比较大&#xff0c;比…

RT_Thread内核机制学习(四)队列

队列 队列中每个消息块都有一个头部&#xff0c;指向下一个消息块。 消息块的内存是连在一起的&#xff0c;但是是用链表组织的。 struct rt_messagequeue {struct rt_ipc_object parent; /**< inherit from ipc_object */void *m…

《独立开发者首次飞行指南》终于来了!!

大家好&#xff0c;我是彭涛。 现在&#xff0c;每年都有各家大厂裁员&#xff0c;各类中小厂跑路&#xff0c;失业人数越来越多的新闻。如果&#xff0c;我们身背房贷&#xff0c;我们应该都会非常焦虑。大环境下&#xff0c;我们不得不逐一探索新的赚钱之道&#xff0c;前段时…

anaconda环境迁移

conda环境迁移第一步 进入anaconda安装文件夹&#xff0c;然后进入envs文件夹&#xff0c;下面的每一个文件夹都是你创建的环境&#xff0c; 准备一个u盘之类的&#xff0c;把整个文件夹复制下来&#xff0c;然后打开另外一台机器&#xff0c;把同样的文件夹复制到同样的文件夹…

JS设置视频播放速度

方法 一&#xff1a;示例代码 document.querySelector(video).playbackRate 5; 进入到要加速的视频页面按F12打开控制控制台输入代码并回车 方法二&#xff1a;示例代码 document.getElementsByTagName("video")[0].playbackRate 5; 进入到要加速的视频页面按F…

钉钉消息已读、未读咋实现的嘞?

前言 一款app&#xff0c;消息页面有&#xff1a;钱包通知、最近访客等各种通知类别&#xff0c;每个类别可能有新的通知消息&#xff0c;实现已读、未读功能&#xff0c;包括多少个未读&#xff0c;这个是怎么实现的呢&#xff1f;比如用户A访问了用户B的主页&#xff0c;难道…

Java实现获取微信小程序scheme码报错

如标题所见&#xff0c;使用Java获取小程序scheme时除了出现文档中的常见错误&#xff0c;我将我调试的时候遇到的错误和解决方式分享出来方便大家少花一部分时间解决该问题。&#xff08;往下划有结论节省时间&#xff09;。 获取scheme码之前需要先获取access_token&#xff…

Vue生命周期(详细)

生命周期 图&#xff1a; 可以理解vue生命周期就是指vue实例从创建到销毁的过程&#xff0c;在vue中分为8个阶段&#xff1a;创建前/后&#xff0c;载入前/后&#xff0c;更新前/后&#xff0c;销毁前/后。 一、创建&#xff08;实例&#xff09; 1、beforeCreate&#xff1a…

问道管理:市盈率怎么计算?

市盈率是衡量一家公司股票价格是否合理的重要目标之一&#xff0c;核算市盈率的公式是将一家公司的股票价格除以每股收益&#xff0c;也便是市盈率 股票价格 每股收益。市盈率能够告诉你一个公司的股票价格是否高估或轻视&#xff0c;是投资者在买入或卖出一家公司股票时需求…

拒绝摆烂!C语言练习打卡第七天

&#x1f525;博客主页&#xff1a;小王又困了 &#x1f4da;系列专栏&#xff1a;每日一练 &#x1f31f;人之为学&#xff0c;不日近则日退 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、选择题 &#x1f4dd;1.第一题 &#x1f4dd;2.第二题 &#x1f4d…

UE5.1 透明渲染流程框架图

相关文章&#xff1a; UE 透明物体绘制准备_sh15285118586的博客-CSDN博客 透明直接光和间接光生成_sh15285118586的博客-CSDN博客 Scene:Translucency-Translucency(AfterDOF)_sh15285118586的博客-CSDN博客 Scene:Translucency-Distortion &PostProcessing:ComposeTran…

系列十四、Chrome浏览器安装JSONView插件

一、下载JSONView插件 说明&#xff1a;如果能够上外网的话&#xff0c;在Chrome应用商店下载JSON格式化插件安装即可 我分享的链接&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1H8VUH8e9Tw7JqrlJEBnQQg?pwdyyds 提取码&#xff1a;yyds 二、安装 解压》Chrome…

MybatisPlus-Generator

文章目录 一、前言二、MybatisPlus代码生成器1、引入依赖2、编写生成代码3、配置说明3.1、全局配置(GlobalConfig)3.2、包配置(PackageConfig)3.3、模板配置(TemplateConfig)3.4、策略配置(StrategyConfig)3.4.1、Entity 策略配置3.4.2、Controller 策略配置3.4.3、Service 策略…

IDEA快速设置全局JDK

出bug 了 JDK 不识别了&#xff0c;才想起来要设置jdk &#xff0c;现在一般查到的都是setting 设置全局的idea设置。但是老玩家的我怎么会不知道有一个设置全局jdk 的一个设置 setings 设置是对idea 的基础设置。 但是还有一个隐藏页面快捷键【CtrlAltShiftS】 接下来自己研究…

B080-RabbitMQ

目录 RabbitMQ认识概念使用场景优点AMQP协议JMS RabbitMQ安装安装elang安装RabbitMQ安装管理插件登录RabbitMQ消息队列的工作流程 RabbitMQ常用模型HelloWorld-基本消息模型生产者发送消息导包获取链接工具类消息的生产者 消费者消费消息模拟消费者手动签收消息 Work QueuesSen…

docker启动paddlespeech服务,并使用接口调用

一、检查docker容器是否启动 1.输入命令 systemctl status docker 启动 systemctl start docker 守护进程重启 sudo systemctl daemon-reload 重启docker服务 systemctl restart docker 重启docker服务 sudo service docker restart 关闭docker service docker…

【Nacos】使用Nacos进行服务发现、配置管理

Nacos Nacos是 Dynamic Naming and Configuration Service 的首字母简称&#xff0c;一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 版本说明&#xff1a;版本说明 alibaba/spring-cloud-alibaba Wiki GitHub <properties><java.version>…

21 Linux高级篇-日志管理

21 Linux高级篇-日志管理 文章目录 21 Linux高级篇-日志管理21.1 系统常用的日志21.2 日志管理服务rsyslogd21.2.1 *日志记录原理21.2.2 配置文件/etc/rsyslog.conf21.2.3 日志文件格式 21.3 日志轮替21.3.1 配置文件/etc/logrotate.conf & /etc/logrotate.d/21.3.2 可执行…

memcpy 函数

目录 函数介绍&#xff1a; 函数解析&#xff1a; memcpy函数复制的数据长度 内存重叠 凑不出元素的字节数 模拟memcpy 函数介绍&#xff1a; memcpy函数是一个用于内存复制的函数&#xff0c;声明在 string.h 中&#xff08;C是 cstring&#xff09;。 其原型是&…