Java8新特性 - Stream - 20 - Stream的并行流与安全性处理

1.说明

本文主要对并行流的常规操作进行了纪录,并没有详细的讲解。

2.代码

package com.northcastle.I_stream;

/**
 * author : northcastle
 * createTime:2022/3/11
 */

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
import java.util.stream.Stream;

/**
 * 串行流 : 在一个线程上面执行
 * 并行流 : 多个线程同时处理一个流
 *    parallelStream : 就是一个并行流,通过ForkJoinPool,利用多线程的方式,提高流的处理速度
 */
public class StreamParallel {

    /**
     * 1.体会串行流 : 在同一个线程内,按顺序执行
     */
    @Test
    public void test01(){
        String[] strs = {"aaa","bbb","ccc","ddd","eee","fff"};
        Stream.of(strs).map(s -> {
            System.out.println(Thread.currentThread()+" : "+s);
            return Thread.currentThread().getName()+"->"+s;
        }).count();
    }

    /**
     * 2.获取并行流的两种方式
     *   1.通过Collection接口的parallelStream() 获取一个并行流
     *   2.通过已有的串行流转换为并行流 parallel() 方法
     */
    @Test
    public void test02(){
        //方式一 : parallelStream() 方法
        ArrayList<String> list = new ArrayList<>();
        Stream<String> parallelStream01 = list.parallelStream();
        System.out.println(parallelStream01);

        //方式二 :串行流转化为并行流
        Stream<String> stream = list.stream();
        Stream<String> parallelStream02 = stream.parallel();
        System.out.println(parallelStream02);
    }

    /**
     * 3.并行流的使用(其实与串行流的使用方式是一样的)
     *   此时能体会到 ForkJoinPool的线程池中的线程
     */
    @Test
    public void test03(){
        String[] strs = {"aaa","bbb","ccc","ddd","eee","fff"};

        Stream.of(strs).parallel() // 串行流转换为并行流
                .map(s -> {
            System.out.println(Thread.currentThread()+" : "+s);
            return Thread.currentThread().getName()+"->"+s;
        }).count();

    }

    /*下面开始对比一下 普通的for循环、串行流、并行流 的执行效率*/

    long beginTime = 0; // 开始时间
    long endTime = 0;//结束时间
    long times = 500000000; // 运行次数
    @Before
    public void before(){
        beginTime = System.currentTimeMillis();
        System.out.println("begin time : "+beginTime);
    }

    /**
     * 普通for循环 - 374
     * begin time : 1647012437913
     * sum = 124999999750000000
     * end time : 1647012438287
     * cost : 374
     */
    @Test
    public void commonFor(){
        long sum = 0;
        for (int i = 0; i <= times ; i++) {
            sum+=i;
        }
        System.out.println("sum = "+sum);
    }

    /**
     * 串行流 - 320
     * begin time : 1647056179951
     * sum = 125000000250000000
     * end time : 1647056180271
     * cost : 320
     */
    @Test
    public void serialStream(){
        long reduce = LongStream.rangeClosed(0, times)
                .reduce(0, Long::sum);
        System.out.println("sum = "+ reduce);
    }

    /**
     * 并行流 - 239
     * begin time : 1647056314702
     * sum = 125000000250000000
     * end time : 1647056314941
     * cost : 239
     */
    @Test
    public void parallelStream(){
        long reduce = LongStream.rangeClosed(0, times)
                .parallel() // 获取一个串行的流
                .reduce(0, Long::sum);
        System.out.println("sum = "+reduce);
    }

    @After
    public void after(){
        endTime = System.currentTimeMillis();
        System.out.println("end time : "+endTime);
        System.out.println("cost : "+(endTime - beginTime));
    }

    /*上面是 普通for循环、串行流、并行流 三者的执行效率的对比,通过运行发现,在硬件强大的基础上,执行效率并不会差很多*/


    /*下面是 线程安全问题的操作*/

    /**
     * 1.体会并行流的问题
     * 使用并行流向一个集合中放入元素
     */
    @Test
    public void parallelBug(){
        ArrayList<Long> list01 = new ArrayList<>();
        ArrayList<Long> list02 = new ArrayList<>();

        int times = 1000; // 定义元素的多少
        LongStream.rangeClosed(0, times).forEach(list01::add);
        System.out.println("串行流元素数量 = "+list01.size());

        LongStream.rangeClosed(0,times).parallel().forEach(list02::add);
        System.out.println("并行流元素数量 = "+list02.size());
    }

    /**
     * 并行流的解决方案一 : 加同步锁
     */
    @Test
    public void parallelResolve01(){

        ArrayList<Long> list01 = new ArrayList<>();
        ArrayList<Long> list02 = new ArrayList<>();

        int times = 1000; // 定义元素的多少
        LongStream.rangeClosed(0, times).forEach(list01::add);
        System.out.println("串行流元素数量 = "+list01.size());

        Object obj = new Object(); // 定义一个对象锁
        LongStream.rangeClosed(0,times)
                .parallel()
                .forEach(i ->{
                    synchronized (obj){
                        list02.add(i);
                    }
                });
        System.out.println("并行流元素数量 = "+list02.size());

    }
    /**
     * 并行流的解决方案二 : 使用线程安全的容器
     */
    @Test
    public void parallelResolve02(){

        ArrayList<Long> list01 = new ArrayList<>();
        Vector<Long> list02 = new Vector<>();

        int times = 1000; // 定义元素的多少
        LongStream.rangeClosed(0, times).forEach(list01::add);
        System.out.println("串行流元素数量 = "+list01.size());

        LongStream.rangeClosed(0,times)
                .parallel()
                .forEach(list02::add);
        System.out.println("并行流元素数量 = "+list02.size());

    }

    /**
     * 并行流的解决方案三 : 将线程不安全的容器 转换 为线程安全的容器
     */
    @Test
    public void parallelResolve03(){

        ArrayList<Long> list01 = new ArrayList<>();
        ArrayList<Long> list02 = new ArrayList<>();
        List<Long> synchronizedList02 = Collections.synchronizedList(list02); // 将list02 转为 线程安全的容器

        int times = 1000; // 定义元素的多少
        LongStream.rangeClosed(0, times).forEach(list01::add);
        System.out.println("串行流元素数量 = "+list01.size());

        LongStream.rangeClosed(0,times)
                .parallel()
                .forEach(synchronizedList02::add);
        System.out.println("并行流元素数量 = "+list02.size());

    }

    /**
     * 并行流的解决方案四 :通过toArray() 或者 Collections.toList()等方法实现转换
     *
     */
    @Test
    public void parallelResolve04(){

        ArrayList<Long> list01 = new ArrayList<>();
        List<Long> list02 = new ArrayList<>();

        int times = 1000; // 定义元素的多少
        LongStream.rangeClosed(0, times).forEach(list01::add);
        System.out.println("串行流元素数量 = "+list01.size());

        list02 = LongStream.rangeClosed(0, times)
                .parallel() // 转成 并行流
                .boxed() // 把一个 long 类型转换成了 Long 封装类型的数据
                .collect(Collectors.toList());
        System.out.println("并行流元素数量 list02 = "+list02.size());

        Object[] objects = LongStream.rangeClosed(0, times)
                .parallel() // 转成 并行流
                .boxed() // 把一个 long 类型转换成了 Long 封装类型的数据
                .toArray();
        System.out.println("并行流元素数量 objects = "+objects.length);

    }

    /*上面是 线程安全问题的操作*/


}

3.完成

Congratulatioins!
You are one step closer to success!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值