• Fork/Jion框架详解



    Fork/Jion框架可以干什么

    如果你要处理1万条数据,但是你的能力暂时还不够,一个简单快捷的办法就是你可以把每次只处理100条,等到处理100次之后再把所有的结果聚合起来你就处理完了这1万条数据。

    Fork/Join就是是Java7提供的原生多线程并行处理框架,它的基本思想就是将大任务分割成小任务,最后将小任务聚合起来得到结果。


    如何使用Fork/Jion框架

    我们要使用ForkJoin框架,首先要创建一个ForkJoin任务。它提供在任务中执行fork()和join的操作机制。
    fork用来创建子线程,可以让程序多一个执行分枝,jion在我们之前文章中已经提到了,那就是等待结果。
    通常我们可以按需继承如下两个类来使用Fork/Jion框架:

    1. RecursiveAction,用于没有返回结果的任务

    2. RecursiveTask,用于有返回值的任务


    代码示例

    下方是一个使用Fork/Jion框架计算1到10000的所有数值的和的一个简单的代码示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    public class ForkJionDemo extends RecursiveTask<Integer> {
    //任务拆分阈值
    public static final int threshold = 100;
    //计算起始值
    private int start;
    //计算结束值
    private int end;

    public ForkJionDemo(int start, int end) {
    this.start = start;
    this.end = end;
    }

    @Override
    protected Integer compute() {
    int sum = 0;
    //计算任务是否需要拆分
    boolean canCompute = (end - start) <= threshold;
    if (canCompute) {
    //无需拆分则执行任务累计
    for (int i = start; i <= end; i++) {
    sum += i;
    }
    } else {
    List<ForkJionDemo> forkJionDemoList=new ArrayList<>();
    //将任务拆分成100份
    for(int i=0;i<100;i++){
    //计算这个一份任务要计算的起点和终点,如果终点大于最大值则使用最大值为终点
    int last=(start+threshold)>end?end:(start+threshold);
    ForkJionDemo forkJionDemo = new ForkJionDemo(start, last);
    //下一份任务的起点要更新
    start+=threshold+1;
    forkJionDemoList.add(forkJionDemo);
    //提交子任务
    forkJionDemo.fork();
    }
    //汇总拆分完毕后的任务结果
    for(ForkJionDemo forkJionDemo:forkJionDemoList){
    sum += forkJionDemo.join();
    }
    }
    return sum;
    }

    public static void main(String[] args) {
    //构造一个任务线程池
    ForkJoinPool forkjoinPool = new ForkJoinPool();
    //创建一个计算1到10000之间所有数的和的任务
    ForkJionDemo forkJionDemo = new ForkJionDemo(1, 10000);
    //将任务提交到任务线程池
    Future<Integer> result = forkjoinPool.submit(forkJionDemo);
    try {
    //打印最后计算结果
    System.out.println(result.get());
    } catch (InterruptedException e) {
    e.printStackTrace();
    } catch (ExecutionException e) {
    e.printStackTrace();
    }
    }
    }


    使用Fork/Jion框架需要注意的点

    如果使用Fork/Jion框架计算的任务量特别庞大时很可能会出现以下2种情况:
    fork的线程越来越多导致性能严重下降
    函数调用层次越来越深导致栈溢出

    本文所有源码参见:https://github.com/shiyujun/syj-study-demo

    博客所有文章首发于公众号《Java学习录》转载请保留
    扫码关注公众号即可领取2000GJava学习资源


    Fork/Jion框架可以干什么

    如果你要处理1万条数据,但是你的能力暂时还不够,一个简单快捷的办法就是你可以把每次只处理100条,等到处理100次之后再把所有的结果聚合起来你就处理完了这1万条数据。

    Fork/Join就是是Java7提供的原生多线程并行处理框架,它的基本思想就是将大任务分割成小任务,最后将小任务聚合起来得到结果。


    如何使用Fork/Jion框架

    我们要使用ForkJoin框架,首先要创建一个ForkJoin任务。它提供在任务中执行fork()和join的操作机制。
    fork用来创建子线程,可以让程序多一个执行分枝,jion在我们之前文章中已经提到了,那就是等待结果。
    通常我们可以按需继承如下两个类来使用Fork/Jion框架:

    1. RecursiveAction,用于没有返回结果的任务

    2. RecursiveTask,用于有返回值的任务


    代码示例

    下方是一个使用Fork/Jion框架计算1到10000的所有数值的和的一个简单的代码示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    public class ForkJionDemo extends RecursiveTask<Integer> {
    //任务拆分阈值
    public static final int threshold = 100;
    //计算起始值
    private int start;
    //计算结束值
    private int end;

    public ForkJionDemo(int start, int end) {
    this.start = start;
    this.end = end;
    }

    @Override
    protected Integer compute() {
    int sum = 0;
    //计算任务是否需要拆分
    boolean canCompute = (end - start) <= threshold;
    if (canCompute) {
    //无需拆分则执行任务累计
    for (int i = start; i <= end; i++) {
    sum += i;
    }
    } else {
    List<ForkJionDemo> forkJionDemoList=new ArrayList<>();
    //将任务拆分成100份
    for(int i=0;i<100;i++){
    //计算这个一份任务要计算的起点和终点,如果终点大于最大值则使用最大值为终点
    int last=(start+threshold)>end?end:(start+threshold);
    ForkJionDemo forkJionDemo = new ForkJionDemo(start, last);
    //下一份任务的起点要更新
    start+=threshold+1;
    forkJionDemoList.add(forkJionDemo);
    //提交子任务
    forkJionDemo.fork();
    }
    //汇总拆分完毕后的任务结果
    for(ForkJionDemo forkJionDemo:forkJionDemoList){
    sum += forkJionDemo.join();
    }
    }
    return sum;
    }

    public static void main(String[] args) {
    //构造一个任务线程池
    ForkJoinPool forkjoinPool = new ForkJoinPool();
    //创建一个计算1到10000之间所有数的和的任务
    ForkJionDemo forkJionDemo = new ForkJionDemo(1, 10000);
    //将任务提交到任务线程池
    Future<Integer> result = forkjoinPool.submit(forkJionDemo);
    try {
    //打印最后计算结果
    System.out.println(result.get());
    } catch (InterruptedException e) {
    e.printStackTrace();
    } catch (ExecutionException e) {
    e.printStackTrace();
    }
    }
    }


    使用Fork/Jion框架需要注意的点

    如果使用Fork/Jion框架计算的任务量特别庞大时很可能会出现以下2种情况:
    fork的线程越来越多导致性能严重下降
    函数调用层次越来越深导致栈溢出

    本文所有源码参见:https://github.com/shiyujun/syj-study-demo

     


  • 相关阅读:
    android 异步加载图片缩略图
    Java小工具===》在目录内查找包含××(字符串)的文件,并显示行号
    android 录像和拍照功能
    基于socket的上传下载(Java)精简版
    android 瀑布流简单例子
    创建上下文菜单及监听
    一个简单的win32截图例子
    把位图保存为文件源代码
    进程间通讯 —— 共享内存
    解决WIN32窗口不响应WM_LBUTTONDBLCLK消息
  • 原文地址:https://www.cnblogs.com/zhixiang-org-cn/p/10633778.html
Copyright © 2020-2023  润新知