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. Java流程控制之用户交互Scanner

    Scanner对象 java.util.Scanner是Java5的新特征,可以通过Scanner类来获取用户的输入 #基本语法# Scanner s = new Scanner(System.in) ...

  2. variadic templates (数量不定的模板参数)

    void print() {} // 当只剩下一个参数时,args为空,执行这个版本的print template<typename T, typename... Types> void ...

  3. Unity连接海康摄像头(shader转码)硬解码

    1.第一种方法 之前写过就不写了给个地址 2.第二种方法 用海康的SDK (shader转码) 先上效果 demo下载地址: 点击下载 开启多个摄像头的话 第二种比一种流畅

  4. 解决 使用 params 传递参数 必须 加上 name

    {path:'/blog',name:'blog',params:{is:true}}

  5. 05 js利用ajax向服务器发送请求并返回json值

    创建一个php $json = '';$data = array();$con =mysqli_connect($servername, $username, $password, $dbname); ...

  6. #硬件 #资讯 #科普 #短报 SSD价格跳水根本停不下来!不断刷出新低

    一份来自日本的统计显示,10~12月的初步统计显示,PC市场的指标产品中,256GB TLC颗粒SSD价格再次下跌2美元,现在只有29.5美元.这已经是该指标产品连续5个季度下跌,创下史上心底记录,同 ...

  7. 昨天写了个ATM系统,学了点思想

    昨天上黑马的基础课终结,有个小测验是做个ATM系统 拿到之后我就明白该怎么做了 但是在后面遇到了瓶颈 就是 不知道怎么进入下级菜单 后面稍微看了一下他的做法,学会了 就继续做了,后面就做出来了 他这个 ...

  8. 面向对象ooDay6

    精华笔记: static final常量:应用率高 必须声明同时初始化 由类名打点来访问,不能被改变 建议:常量所有字母都大写,多个单词用_分隔 编译器在编译时会将常量直接替换为具体的数,效率高 何时 ...

  9. ajax高级(请求服务器脚本,数据库, ajxa xml文件)

    请求jsp与请求普通文件不通过的地方,请求jsp可能会传参,比如搜索,用户名,页码这些 html部分:<input type="text" id="txt1&quo ...

  10. 自学JavaDay02_class01

    注释 单行注释: //单行注释 多行注释 /** 多行注释* 多行注释* */ 文档注释 /** * 文档注释 * 文档注释 */ 标识符 关键字 标识符 所有的标识符都应该以字母(A-Z 或者 a- ...