6.4 并行流与并行排序
Java 8中,可以在接口不变的情况下,将流改为并行流。这样,就可以很自然地使用多线程进行集合中的数据处理。
6.4.1 使用并行流过滤数据
现在让我们考虑这么一个简单的案例,我们希望可以统计1~1000000内所有的质数的数量。首先,我们需要一个判断质数的函数:
public class PrimeUtil { public static boolean isPrime(int number) { int tmp = number; if (tmp < 2) { return false; } for (int i = 2; Math.sqrt(tmp) >= i; i++) { if (tmp % i == 0) { return false; } } return true; } }
上述函数给定一个数字,如果这个数字是质数就返回true,否则返回false。
接着,使用函数式编程统计给定范围内所有的质数:
IntStream.range(1, 1000000).filter(PrimeUtil::isPrime).count();
上述代码首先生成一个1到1000000的数字流。接着使用过滤函数,只选择所有的质数,最后进行数量统计。
上述代码是串行的,将它改造成并行计算非常简单,只需要将流并行化即可:
IntStream.range(1, 1000000).parallel().filter(PrimeUtil::isPrime).count();
上述代码中,首先parallel()方法得到一个并行流,接着,在并行流上进行过滤,此时,PrimeUtil.isPrime()函数会被多线程并发调用,应用于流中的所有元素。
6.4.2 从集合得到并行流
在函数式编程中,我们可以从集合得到一个流或者并行流。下面这段代码试图统计集合内所有学生的平均分:
List<Student> ss=new ArrayList<Student>(); double ave=ss.stream().mapToInt(s->s.score).average().getAsDouble();
从集合对象List中,我们使用stream()方法可以得到一个流。如果希望将这段代码并行化,则可以使用parallelStream()函数。
double ave=ss.parallelStream().mapToInt(s->s.score).average().getAsDouble();
可以看到,将原有的串行方式改造成并行执行是非常容易的。
6.4.3 并行排序
除了并行流外,对于普通数组,Java 8中也提供了简单的并行功能。比如,对于数组排序,我们有Arrays.sort()方法。当然这是串行排序,但在Java 8中,我们可以使用新增的Arrays. parallelSort()方法直接使用并行排序。
比如,你可以这样使用:
int[] arr=new int[10000000]; Arrays.parallelSort(arr);
除了并行排序外,Arrays中还增加了一些API用于数组中数据的赋值,比如:
public static void setAll(int[] array, IntUnaryOperator generator)
这是一个函数式味道很浓的接口,它的第2个参数是一个函数式接口。如果我们想给数组中每一个元素都附上一个随机值,则可以这么做:
Random r=new Random(); Arrays.setAll(arr, (i)->r.nextInt());
当然,以上过程是串行的。但是只要使用setAll()对应的并行版本,你就可以很快将它执行在多个CPU上:
Random r=new Random(); Arrays.parallelSetAll (arr, (i)->r.nextInt());
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论