Java 并发编程之ForkJoin框架

 更新时间:2021年11月22日 16:40:18   作者:smileNicky  
这篇文章主要为大家介绍了Java ForkJoin框架,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助,希望能够给你带来帮助

1、什么是ForkJoin框架

ForkJoin框架是java的JUC包里提供的,用于处理一些比较繁重的任务,会将这个大任务分为多个小任务,多个小任务处理完成后会将结果汇总给Result,体现的是一种“分而治之”的思想。第一步,拆分fork任务,将大任务分为多个小任务;第二步,归并join,会将小任务的处理结果进行归并为一个结果。

在这里插入图片描述

2、ForkJoinTask

ForkJoinTask是ForkJoin框架的提供的任务API,ForkJoinTask是一个抽象类,有两个主要的实现类,RecursiveTask和RecursiveAction,其中RecursiveTask和RecursiveAction的主要区别是,RecursiveAction没有返回值,而RecursiveTask是有返回值的

在这里插入图片描述

3、ForkJoinPool

ForkJoinPool类是forkjoin框架的线程池实现,基于ExecutorService接口。这个线程池是jdk1.7才加入的,用于管理线程,执行forkjoin的任务。对于线程池的使用,我们使用ThreadPoolExecutor比较多,可以在idea里看一下uml类图,可以看出ForkJoinPool和ThreadPoolExecutor实现差不多的。

在这里插入图片描述

ForkJoinPool()
ForkJoinPool(int parallelism)
ForkJoinPool(int parallelism, ForkJoinWorkerThreadFactory factory,
 UncaughtExceptionHandler handler, boolean asyncMode)

几个重要的参数:

  • parallelism:并行度,并行执行线程,可用指定,也可以不指定,不指定的情况,是根据cpu核数创建可用的线程
  • ForkJoinWorkerThreadFactory:创建线程的工厂实现
  • UncaughtExceptionHandler :因为未知异常中断的回调处理
  • asyncMode:是否异步,默认情况是false

使用时候,可以直接创建ForkJoinPool,可以不传参,不传参的情况,默认指定的线程并行数为Runtime.getRunTime().availableProcessors();,表示根据cpu核数创建可用线程数

ForkJoinPool forkJoinPool = new ForkJoinPool();
ArraySortTask task = new ArraySortTask(array , 0 , size);
forkJoinPool.submit(task);
task.get();

也是可用传参,对并行度进行指定的public ForkJoinPool(int parallelism), parallelism并行度,并行执行几个线程

将forkjoin任务加入到FrokJoinPool线程池有几种方式

  • execute():调用其 fork 方法在多个线程之间拆分工作。
  • invoke():在ForkJoinPool线程池上调用invoke方法
  • submit():返回一个Future对象,Future可以进行监控,任务完成后返回结果

4、打印斐波那契数列

ForkJoin框架可以用于一些递归遍历的场景,对于斐波那契数列,你可以比较熟悉,因为在面试中有时候经常问到,斐波那契数列的特点就是最后一项的结果等于前面两项的和

package com.example.concurrent.forkjoin;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
/**
 * <pre>
 *      斐波那契数列
 * </pre>
 * <p>
 * <pre>
 * @author nicky.ma
 * 修改记录
 *    修改后版本:     修改人:  修改日期: 2021/10/12 16:22  修改内容:
 * </pre>
 */
public class Fibonacci extends RecursiveTask<Integer>{
    private int n;
    public Fibonacci(int n) {
        this.n = n;
    }
    @Override
    protected Integer compute() {
        if (n <= 1)
            return n;
        Fibonacci f1 = new Fibonacci(n - 1);
        f1.fork();
        Fibonacci f2 = new Fibonacci(n - 2);
        f2.fork();
        return f1.join() + f2.join();
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ForkJoinPool pool = new ForkJoinPool();
        for (int i = 0; i< 10; i++) {
            ForkJoinTask task = pool.submit(new Fibonacci(i));
            System.out.println(task.get());
        }
    }
}

5、ForkJoin归并排序

面试题:快速实现对一个长度百万的数组的排序

难点:可以使用归并排序,多线程如何组织实现归并排序

package com.example.concurrent.forkjoin;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
/**
 * <pre>
 *      大数组排序
 * </pre>
 * <p>
 * <pre>
 * @author mazq
 * 修改记录
 *    修改后版本:     修改人:  修改日期: 2021/10/12 17:04  修改内容:
 * </pre>
 */
public class ArraySortTask extends RecursiveAction{
    final long[] array; final int lo, hi;
    ArraySortTask(long[] array, int lo, int hi) {
        this.array = array; this.lo = lo; this.hi = hi;
    }
    ArraySortTask(long[] array) { this(array, 0, array.length); }
    @Override
    protected void compute() {
        if (hi - lo < THRESHOLD)
            // 少于阀值,使用Arrays.sort 快排
            sortSequentially(lo, hi);
        else {
            /* 归并排序 */
            // 取中间值
            int mid = (lo + hi) >>> 1;
            // 拆分任务
            invokeAll(new ArraySortTask(array, lo, mid),
                    new ArraySortTask(array, mid, hi));
            // 归并结果
            merge(lo, mid, hi);
        }
    }
    // implementation details follow:
    static final int THRESHOLD = 1000;
    void sortSequentially(int lo, int hi) {
        Arrays.sort(array, lo, hi);
    }
    void merge(int lo, int mid, int hi) {
        long[] buf = Arrays.copyOfRange(array, lo, mid);
        for (int i = 0, j = lo, k = mid; i < buf.length; j++)
            array[j] = (k == hi || buf[i] < array[k]) ?
                    buf[i++] : array[k++];
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        int size = 10_000;
        long[] array = new long[size];
        Random random = new Random();
        for (int i = 0; i< size; i++) {
            array[i] = random.nextInt();
        }
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ArraySortTask task = new ArraySortTask(array , 0 , size);
        forkJoinPool.submit(task);
        task.get();
        for (long a : array) {
            System.out.println(a);
        }
    }
}

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

相关文章

  • 如何利用java中String类的substring()字符串截取最后一个字符

    如何利用java中String类的substring()字符串截取最后一个字符

    Java中的String是不可变的类型,因此substring()方法并不会改变原字符串,而是返回了一个新的字符串,这篇文章主要介绍了如何利用java中String类的substring()字符串截取最后一个字符,需要的朋友可以参考下
    2023-11-11
  • Freemarker常用指令使用示例

    Freemarker常用指令使用示例

    这篇文章主要介绍了Freemarker常用指令使用示例,步骤简单,大家参考使用吧
    2013-11-11
  • 简单易用的Spring Boot邮件发送demo

    简单易用的Spring Boot邮件发送demo

    本文将介绍如何使用Spring Boot发送邮件,我们将演示如何配置SMTP邮件服务器,创建一个邮件模板,以及如何使用JavaMailSender发送邮件,我们还将介绍如何测试我们的邮件发送代码
    2023-12-12
  • 解决IDEA开发工具右侧没有Maven工具栏的问题

    解决IDEA开发工具右侧没有Maven工具栏的问题

    这篇文章主要给大家解决了IDEA开发工具右侧没有Maven工具栏的问题,文中有详细的解决步骤,如果有遇到一样问题的小伙伴,可以参考阅读本文
    2023-09-09
  • Arthas在线java进程诊断工具在线调试神器详解

    Arthas在线java进程诊断工具在线调试神器详解

    Arthas是 Alibaba 开源的Java诊断工具,深受开发者喜爱。这篇文章主要介绍了Arthas在线java进程诊断工具 在线调试神器,需要的朋友可以参考下
    2021-11-11
  • java实现定制数据透视表的示例详解

    java实现定制数据透视表的示例详解

    数据透视表(Pivot Table)是一种数据分析工具,通常用于对大量数据进行汇总、分析和展示,本文主要介绍了如何使用Java将计算项添加到数据透视表中,感兴趣的可以了解下
    2023-12-12
  • Gitlab CI-CD自动化部署SpringBoot项目的方法步骤

    Gitlab CI-CD自动化部署SpringBoot项目的方法步骤

    本文主要记录如何通过Gitlab CI/CD自动部署SpringBoot项目jar包。文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-07-07
  • mybatis QueryWrapper的条件构造之apply、last、select解析

    mybatis QueryWrapper的条件构造之apply、last、select解析

    这篇文章主要介绍了mybatis QueryWrapper的条件构造之apply、last、select,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • MyBatis动态创建表的实例代码

    MyBatis动态创建表的实例代码

    在项目需求中,我们经常会遇到动态操作数据表的需求,常见的我们会把日志、设备实时位置信息等存入数据表,并且以一定时间段生成一个表来存储。接下来通过本文给大家介绍MyBatis动态创建表的方法,感兴趣的朋友一起看看吧
    2018-07-07
  • 浅析Java线程的中断机制

    浅析Java线程的中断机制

    本篇文章通过代码实例给大家分享了学习Java线程的中断机制的一些心得内容,有兴趣的朋友学习下吧。
    2017-12-12

最新评论