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!