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. js 时间 日期

    date.getYear(); // 获取当前年份(2 位) date.getFullYear(); // 获取完整的年份(4 位, 1970-????) date.getMonth(); // 获取 ...

  2. opencv对图片画框写文字

    业务背景:对图片进行画框后调用排序方法按照"从上到下,从左到右"对已经画的框进行排序.排序方法当前有缺陷,修复后需要验证. 目前有如下信息: 原始图片地址 图片对应的每个框的坐标( ...

  3. Windows MFC HTTP POST请求 函数流程

    Windows MFC HTTP POST请求 函数流程 1 CString m_strHttpUrl(_T("http://10.200.80.86:8090/course/upload& ...

  4. RN 使用react-navigation写可以滚动的横向导航条

    在react-native中写横向导航条,首选肯定是react-navigation的createMaterialTopTabNavigator,附上官方文档链接.https://reactnavig ...

  5. 使用signalr不使用连接服务器和前台的js的方法

    1:使用这种方式,,就不需要前后台链接的js 2:新建一个empty的MVC项目 3:新建一个controller和index.html 4: 新建一个signalr 集线器类名为PersonHub, ...

  6. TypeScript系列 -> 遇到报错 Cannot find name ‘console‘. Do you need to change your target library?ging the ‘lib‘ compiler option

    学习ts遇到的报错 Cannot find name 'console'. Do you need to change your target library?ging the 'lib' compi ...

  7. 1 Could not resolve XML resource [null] with public ID [null]

    启动Tomcat报错: Java.io.FileNotFoundException: Could not resolve XML resource [null] with public ID [nul ...

  8. sequelize的创建接口以及模糊查询

    第一步: 在routes里面复制index.js更改为xxx.js(例如arctile.js) res.json()返回的就是json文件 第二步: 在views里app.js引用路由 第三步:查找数 ...

  9. CSS之 font

    font:font-style font-weight font-size/line-height font-family的简写.顺序不能乱 **eg ** font:italic bold 30px ...

  10. Tesstwo9.1.0配置步骤

    一,配置步骤 环境:Tesstwo9.1.0+Android10(华为)+Android11(模拟器) 1.查看tess-two的最新版本(GitHub - rmtheis/tess-two: For ...