JDK7并行计算框架介绍一 Fork/Join概述(官方原版-英文)

简介: Fork/Join New in the Java SE 7 release, the fork/join framework is an implementation of the ExecutorService interface that helps you take advantage of multiple processors.

Fork/Join

New in the Java SE 7 release, the fork/join framework is an implementation of the ExecutorService interface that helps you take advantage of multiple processors. It is designed for work that can be broken into smaller pieces recursively. The goal is to use all the available processing power to enhance the performance of your application.

As with any ExecutorService, the fork/join framework distributes tasks to worker threads in a thread pool. The fork/join framework is distinct because it uses a work-stealing algorithm. Worker threads that run out of things to do can steal tasks from other threads that are still busy.

The center of the fork/join framework is the ForkJoinPool class, an extension of AbstractExecutorService. ForkJoinPool implements the core work-stealing algorithm and can execute ForkJoinTasks.

Basic Use

Using the fork/join framework is simple. The first step is to write some code that performs a segment of the work. Your code should look similar to this:

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

Wrap this code as a ForkJoinTask subclass, typically as one of its more specialized types RecursiveTask(which can return a result) or RecursiveAction.

After your ForkJoinTask is ready, create one that represents all the work to be done and pass it to the invoke() method of a ForkJoinPool instance.

Blurring for Clarity

To help you understand how the fork/join framework works, consider a simple example. Suppose you want to perform a simple blur on an image. The original source image is represented by an array of integers, where each integer contains the color values for a single pixel. The blurred destination image is also represented by an integer array with the same size as the source.

Performing the blur is accomplished by working through the source array one pixel at a time. Each pixel is averaged with its surrounding pixels (the red, green, and blue components are averaged), and the result is placed in the destination array. Here is one possible implementation:

public class ForkBlur extends RecursiveAction {
    private int[] mSource;
    private int mStart;
    private int mLength;
    private int[] mDestination;
  
    // Processing window size, should be odd.
    private int mBlurWidth = 15;
  
    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++) {
            // Calculate average.
            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;
            }
          
            // Re-assemble destination pixel.
            int dpixel = (0xff000000     ) |
                   (((int)rt) << 16) |
                   (((int)gt) <<  8) |
                   (((int)bt) <<  0);
            mDestination[index] = dpixel;
        }
    }
  
  ...

Now you implement the abstract compute() method, which either performs the blur directly or splits it into two smaller tasks. A simple array length threshold helps determine whether the work is performed or split.

protected static int sThreshold = 100000;

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));
}

If the previous methods are in a subclass of the RecursiveAction class, setting it up to run in a ForkJoinPool is straightforward.

Create a task that represents all of the work to be done.

// source image pixels are in src
// destination image pixels are in dst
ForkBlur fb = new ForkBlur(src, 0, src.length, dst);

Create the ForkJoinPool that will run the task.

ForkJoinPool pool = new ForkJoinPool();

Run the task.

pool.invoke(fb);

For the full source code, including some extra code that shows the source and destination images in windows, see the ForkBlur class.

官网地址:http://gee.cs.oswego.edu/dl/concurrency-interest/


作者:张子良
出处:http://www.cnblogs.com/hadoopdev
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

相关文章
|
3月前
|
JSON 自然语言处理 Java
这款轻量级 Java 表达式引擎,真不错!
AviatorScript 是一个高性能、轻量级的脚本语言,基于 JVM(包括 Android 平台)。它支持数字、字符串、正则表达式、布尔值等基本类型,以及所有 Java 运算符。主要特性包括函数式编程、大整数和高精度运算、完整的脚本语法、丰富的内置函数和自定义函数支持。适用于规则判断、公式计算、动态脚本控制等场景。
|
9月前
|
Rust 监控 安全
【专栏】`ripgrep`(rg)是Linux下快速、内存高效的文本搜索工具,用Rust编写,支持PCRE2正则表达式
【4月更文挑战第28天】`ripgrep`(rg)是Linux下快速、内存高效的文本搜索工具,用Rust编写,支持PCRE2正则表达式。相比`grep`,它在处理大文件和复杂模式时更具优势。安装`rg`可通过软件包管理器,如在Debian系系统中使用`sudo apt install ripgrep`。基本用法包括简单搜索、递归搜索、忽略大小写、显示行号等。高级功能包括固定字符串搜索、多文件匹配、并行搜索、排除选项和区域搜索。适用于日志分析、代码审查等场景,是提升工作效率的利器。
749 4
|
9月前
|
JavaScript Java 测试技术
基于Java的中文学习系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的中文学习系统的设计与实现(源码+lw+部署文档+讲解等)
55 0
|
9月前
|
JavaScript Java 测试技术
基于Java的在线日语培训平台的设计与实现(源码+lw+部署文档+讲解等)
基于Java的在线日语培训平台的设计与实现(源码+lw+部署文档+讲解等)
68 0
|
9月前
火山中文编程(PC) -- 类的介绍
火山中文编程(PC) -- 类的介绍
88 0
火山中文编程(PC) -- 类的介绍
|
9月前
|
Windows
火山中文编程 -- 第一个windows程序
火山中文编程 -- 第一个windows程序
50 0
|
iOS开发
[OC Runtime编程指南_翻译]二、运行时版本和平台
[OC Runtime编程指南_翻译]二、运行时版本和平台
167 0
|
缓存 Java API
【Java并发编程实战14】构建自定义同步工具(Building-Custom-Synchronizers)(中)
JDK包含许多存在状态依赖的类,例如FutureTask、Semaphore和BlockingQueue,他们的一些操作都有前提条件,例如非空、任务已完成等。
126 0
|
缓存 安全 Java
【Java并发编程实战14】构建自定义同步工具(Building-Custom-Synchronizers)(上)
JDK包含许多存在状态依赖的类,例如FutureTask、Semaphore和BlockingQueue,他们的一些操作都有前提条件,例如非空、任务已完成等。
138 0

热门文章

最新文章