java8提供一个fork/join framework,fork/join框架是ExecutorService接口的一个实现,它可以帮助你充分利用你电脑中的多核处理器,它的设计理念是将一个任务分割成多个可以递归执行的小任务,这些小任务可由不同的处理器进行并行执行,显然这样设计的一个目的就是提高应用的性能。

fork/join框架的和兴是ForkJoinPool类,是AbstractExecutorService类的扩展,它继承了核心的并行执行算法,可以执行ForkJoinTask进程。基本用法可以如下伪代码:

if (my portion of the work is small enough)
do the work directly
else
split my work into two pieces
invoke the two pieces and wait for the results

将上面的代码通过ForkJoinTask子类进行封装,通常继承ForkJoinTask更具体的子类来实现,如RecursiveTask或者RecursiveAction,当子类创建完毕,再创建一个表示要处理的任务的对象,将它作为一个参数传递给ForkJoinPool实例的invoke()方法。官方文档给了一个对照片进行模糊处理的示例,以这个示例为切入点了解fork/join操作,在对照片进行模糊处理时,思路是将一个图片转成一个数组,这个数组中的每个值代表一个像素,然后对这个像素进行处理,显然将图片转成的数组将会是一个很大的数组,为了加快处理,可以对数组进行切割,切割成一个个小的数组,然后对这个小的数组进行并行处理,将处理后的结果再合并成一个大的结果返给用户,代码如下:

class ForkBlur extends RecursiveAction {

    private int[] mSource;
private int mStart;
private int mLength;
private int[] mDestination;
private int mBlurWidth = 15; // Processing window size, should be odd. public ForkBlur(int[] src, int start, int length, int[] dst) {
mSource = src;
mStart = start;
mLength = length;
mDestination = dst;
} // 计算原图片的平均像素, 将结果写道目的数组中.
protected void computeDirectly() {
int sidePixels = (mBlurWidth - 1) / 2;
for (int index = mStart; index < mStart + mLength; index++) {
// 计算平均值.
float rt = 0, gt = 0, bt = 0;
for (int mi = -sidePixels; mi <= sidePixels; mi++) {
int mindex = Math.min(Math.max(mi + index, 0), mSource.length - 1);
int pixel = mSource[mindex];
rt += (float) ((pixel & 0x00ff0000) >> 16) / mBlurWidth;
gt += (float) ((pixel & 0x0000ff00) >> 8) / mBlurWidth;
bt += (float) ((pixel & 0x000000ff) >> 0) / mBlurWidth;
} // 重新组合目标像素.
int dpixel = (0xff000000)
| (((int) rt) << 16)
| (((int) gt) << 8)
| (((int) bt) << 0);
mDestination[index] = dpixel;
}
}
//定义计算的阈值
protected static int sThreshold = 10000; @Override
protected void compute() {
//长度小于指定的阈值,则直接进行计算
if (mLength < sThreshold) {
computeDirectly();
return;
}
//进行切分
int split = mLength / 2;
//并行执行所有的任务
invokeAll(new ForkBlur(mSource, mStart, split, mDestination),
new ForkBlur(mSource, mStart + split, mLength - split,
mDestination));
} // Plumbing follows.
public static void main(String[] args) throws Exception {
String srcName = "C:\\Users\\Administrator\\Desktop\\信息文件\\研究院工作\\个人信息\\aaa.jpg";
File srcFile = new File(srcName);
BufferedImage image = ImageIO.read(srcFile); System.out.println("Source image: " + srcName); BufferedImage blurredImage = blur(image); String dstName = "C:\\Users\\Administrator\\Desktop\\信息文件\\研究院工作\\个人信息\\bbb.jpg";
File dstFile = new File(dstName);
ImageIO.write(blurredImage, "jpg", dstFile); System.out.println("Output image: " + dstName); } public static BufferedImage blur(BufferedImage srcImage) {
int w = srcImage.getWidth();
int h = srcImage.getHeight(); int[] src = srcImage.getRGB(0, 0, w, h, null, 0, w);
int[] dst = new int[src.length]; System.out.println("Array size is " + src.length);
System.out.println("Threshold is " + sThreshold); int processors = Runtime.getRuntime().availableProcessors();
System.out.println(Integer.toString(processors) + " processor"
+ (processors != 1 ? "s are " : " is ")
+ "available"); //创建目标任务对象
ForkBlur fb = new ForkBlur(src, 0, src.length, dst);
//创建任务执行对象
ForkJoinPool pool = new ForkJoinPool(); long startTime = System.currentTimeMillis();
//执行模糊操作
pool.invoke(fb);
long endTime = System.currentTimeMillis(); System.out.println("Image blur took " + (endTime - startTime) +
" milliseconds."); BufferedImage dstImage =
new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
dstImage.setRGB(0, 0, w, h, dst, 0, w); return dstImage;
}
}

上面的代码中,ForkBlur任务继承RecursiveAction抽象类,它的执行过程整体分为三步:

1、创建一个表示需要执行动作的任务:ForkBlur fb=new ForkBlur(...)

2、创建ForkJoinPool对象,以触发任务的执行:ForkJoinPool pool=new ForkJoinPool();

3、执行任务 pool.invoke(fb)

并行计算在流中也有很多引用,它的思想是:java会将流分割成多分子流,聚合操作会以并行的形式遍历处理这些子流,最后将结果汇合成一个结果,在创建平行流的时候需要调用paralleStream()方法指明创建并行流:

double average = roster

    .parallelStream()
.filter(p -> p.getGender() == Person.Sex.MALE)
.mapToInt(Person::getAge)
.average()
.getAsDouble();

java中的并发归约操作,前面讲到,如果将人按照性别的方式进行区分,则归约操作如下:

Map<Person.Sex, List<Person>> byGender =
roster
.stream()
.collect(
Collectors.groupingBy(Person::getGender)); 

上面的代码的结果和下面的操作方式是等价的:

ConcurrentMap<Person.Sex, List<Person>> byGender =

    roster
.parallelStream()
.collect(
Collectors.groupingByConcurrent(Person::getGender)); 

上面的操作方式称为并发归约操作(concurrent reduction),如果以下条件均满足,则一个包含collect操作的管道就是并发归约操作:

1、流是并行的,stream is parallel

2、collect操作的参数,也就是待操作的集合需要有Collector.Characteristics.CONCURRENT特征,查看一个集合的特征,可以调用Collector.characteristics方法

3、无论流是无序的,还是集合具有Collector.Characteristics.UNORDERED的特征,为了保证流是无序的,可以调用BaseStream.unordered操作。

一个管道在处理流的顺序取决于这个流值顺序执行的还是并行执行的(in serial or in parallel)、流的源和中间操作;例如打印一个list集合中的元素,这里使用forEach操作,代码如下: 

Integer[] intArray = {1, 2, 3, 4, 5, 6, 7, 8 };
List<Integer> listOfIntegers =
new ArrayList<>(Arrays.asList(intArray)); System.out.println("listOfIntegers:");
listOfIntegers
.stream()
.forEach(e -> System.out.print(e + " "));
System.out.println(""); System.out.println("listOfIntegers sorted in reverse order:");
Comparator<Integer> normal = Integer::compare;
Comparator<Integer> reversed = normal.reversed();
Collections.sort(listOfIntegers, reversed);
listOfIntegers
.stream()
.forEach(e -> System.out.print(e + " "));
System.out.println(""); System.out.println("Parallel stream");
listOfIntegers
.parallelStream()
.forEach(e -> System.out.print(e + " "));
System.out.println(""); System.out.println("Another parallel stream:");
listOfIntegers
.parallelStream()
.forEach(e -> System.out.print(e + " "));
System.out.println(""); System.out.println("With forEachOrdered:");
listOfIntegers
.parallelStream()
.forEachOrdered(e -> System.out.print(e + " "));
System.out.println(""); ===========执行结果为============= listOfIntegers:
1 2 3 4 5 6 7 8
listOfIntegers sorted in reverse order:
8 7 6 5 4 3 2 1
Parallel stream:
3 4 1 6 2 5 7 8
Another parallel stream:
6 3 1 5 7 8 4 2
With forEachOrdered:
8 7 6 5 4 3 2 1

上面的代码中,第三和第四个管道的输出结果显然是无序的,而第五个管道使用forEachOrdered方法,这时候无论使用的stream还是parallelStream,都使得执行过程按照执行顺序进行,当然,这也就是失去了并行流的优势了。

以上是java并行处理数据的小示例,判断什么时候使用并行处理也是一个问题,知识是无涯的,不要小看任何东西...

java8-并行计算的更多相关文章

  1. Java8 Lambda表达式教程

    转自:http://blog.csdn.net/ioriogami/article/details/12782141 1. 什么是λ表达式 λ表达式本质上是一个匿名方法.让我们来看下面这个例子: pu ...

  2. Java8部分新特性的学习

    Java8中的新特性 一.Lambda表达式 Lambda表达式可以理解为一种可传递的匿名函数:它没有名称,但又参数列表.函数主体.返回类型,可能还有一个可以抛出的异常列表. 匿名:和匿名类类似的,它 ...

  3. 【读书笔记】《写给大忙人看的Java SE 8》——Java8新特性总结

    虽然看过一些Java 8新特性的资料,但是平时很少用到,时间长了就忘了,正好借着Java 9的发布,来总结下一些Java 8中的新特性. 接口中的默认方法和静态方法 先考虑一个问题,如何向Java中的 ...

  4. Java8一:Lambda表达式教程

    1. 什么是λ表达式 λ表达式本质上是一个匿名方法.让我们来看下面这个例子: public int add(int x, int y) {         return x + y;     } 转成 ...

  5. java8 Stream的实现原理 (从零开始实现一个stream流)

    1.Stream 流的介绍 1.1 java8 stream介绍 java8新增了stream流的特性,能够让用户以函数式的方式.更为简单的操纵集合等数据结构,并实现了用户无感知的并行计算. 1.2  ...

  6. java8新特性--Stream的基本介绍和使用

    什么是Stream? Stream是一个来自数据源的元素队列并可以进行聚合操作. 数据源:流的来源. 可以是集合,数组,I/O channel, 产生器generator 等 聚合操作:类似SQL语句 ...

  7. Java8 使用

    Java8 使用 链接:https://www.jianshu.com/p/936d97ba0362 链接:https://www.jianshu.com/p/41de7b5ac7b9 本文主要总结了 ...

  8. 【java多线程】java8的流操作api和fork/join框架

    原文:https://blog.csdn.net/u011001723/article/details/52794455/ 一.测试一个案例,说明java8的流操作是并行操作 1.代码 package ...

  9. Java8函数之旅 (一) 开始认识lambda

    系列之前我想说的   最近有一段时间没写博客了,这几天回到学校,才闲下来,决定写一写最近学习到的知识,既是为了分享,也是为了巩固.之前看到过一篇调查,调查说的是学习新知识,光只是看的话,知识的获取率只 ...

  10. 《写给大忙人看的Java SE 8》——Java8新特性总结

    阅读目录 接口中的默认方法和静态方法 函数式接口和Lambda表达式 Stream API 新的日期和时间 API 杂项改进 参考资料 回到顶部 接口中的默认方法和静态方法 先考虑一个问题,如何向Ja ...

随机推荐

  1. vue项目的两种构建工具Vue CLI和Vite

    Vue CLI官方项目搭建工具,使用的打包器是webpack,webpack使用的模块化规范是commonjs模块: Vite主要特点是开发环境启动迅速,因为是使用的ES模块,这是在现代浏览器开始原生 ...

  2. golang基本数据类型

    1.整形 默认整数类型为int 变量在选择时应遵循最小化原则 1.1 有符号(int) 类型 取值范围 占用空间(字节) int8 -2^7到 2^7-1 (-128到127) 1 int16 -2^ ...

  3. 微信防红页面JS代码

    将Js代码复制粘贴到你网站所需要的页面,保存即可,完美实现防红,具体未测试,如果需要可以自己测试效果. <meta charset="utf-8″> <meta name= ...

  4. weblogic10.3.1.0安装(windows版)

    转: weblogic10.3.1.0安装(windows版) 安装完成后 配置数据源 然后配置部署项目. myeclipse 配置weblogic

  5. bean实例化三种方式

    实例化bean的方式有三种,如下: 1.无参构造方法实例化 2.工厂静态方法实例化 3.工厂普通方法实例化 此处演示的项目结构如下: 方法一:无参构造方法实例化(注意,该类中不能存在有参构造函数) U ...

  6. 攻防世界Web篇——PHP2

    可以从index.phps中找到网站源码 从源码中得出,要满足admin!=$_GET[id],urldecode($_GET[id]) == admin,两个条件才能得到flag 所以就将admin ...

  7. 攻防世界Web进阶篇——warmup

    打开链接,发现是一张滑稽 查看页面源代码,发现文件 于是打开source.php,发现 打开hint.php,根据提示得知flag在ffffllllaaaagggg文件中 回到source.php,检 ...

  8. 关于C#高阶知识捡漏

    高手掠过!仅仅是整理一下 自动属性:  C#自动属性可以避免原来这样我们手工声明一个私有成员变量以及编写get/set逻辑 代码如下 //Demo: public class User { publi ...

  9. Windows相关产品密钥

    Win7/Win8/Win10系统下Visual Studio 2013各个版本的密钥:Visual Studio Ultimate 2013: BWG7X-J98B3-W34RT-33B3R-JVY ...

  10. 物联网5G工业网关的特点和应用场景

    BMG5100 系列产品,是一款工业级 5G 千兆物联网网关.集数据管理.智能采集.多种协议 转换.5G/4G 无线通信.数据处理转发.VPN 虚拟专网.本地存储.WIFI 覆盖等功能于一体. 产品特 ...