ForkJoin看这篇就够了![通俗易懂]

ForkJoin看这篇就够了![通俗易懂]大家好,我是小黑,一个在互联网苟且偷生的农民工。在JDK1.7中引入了一种新的Fork/Join线程池,它可以将一个大的任务拆分成多个小的任务并行执行并汇总执行结果。Fork/Join采用的是分而治之的基本思想,分而治之就是将一个复杂的任务,按照规定的阈值划分成多个简单的小任务,然后将这些小任务的结果再进行汇总返回,得到最终的任务。分治法分治法是计算机领域常用的算法中的其中一个,主要思想就是将将一个规模为N的问题,分解成K个规模较小的子问题,这些子问题相互独立且与原问题性质相同;求解出子问题的解

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

大家好,我是小黑,一个在互联网苟且偷生的农民工。

在JDK1.7中引入了一种新的Fork/Join线程池,它可以将一个大的任务拆分成多个小的任务并行执行并汇总执行结果。

Fork/Join采用的是分而治之的基本思想,分而治之就是将一个复杂的任务,按照规定的阈值划分成多个简单的小任务,然后将这些小任务的结果再进行汇总返回,得到最终的任务。

分治法

分治法是计算机领域常用的算法中的其中一个,主要思想就是将将一个规模为N的问题,分解成K个规模较小的子问题,这些子问题相互独立且与原问题性质相同;求解出子问题的解,合并得到原问题的解。

解决问题的思路

  • 分割原问题;
  • 求解子问题;
  • 合并子问题的解为原问题的解。

使用场景

二分查找,阶乘计算,归并排序,堆排序、快速排序、傅里叶变换都用了分治法的思想。

ForkJoin并行处理框架

在JDK1.7中推出的ForkJoinPool线程池,主要用于ForkJoinTask任务的执行,ForkJoinTask是一个类似线程的实体,但是比普通线程更轻量。

我们来使用ForkJoin框架完成以下1-10亿求和的代码。

public class ForkJoinMain { 
   
    public static void main(String[] args) throws ExecutionException, InterruptedException { 
   
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTask<Long> rootTask = forkJoinPool.submit(new SumForkJoinTask(1L, 10_0000_0000L));
        System.out.println("计算结果:" + rootTask.get());
    }
}

class SumForkJoinTask extends RecursiveTask<Long> { 
   
    private final Long min;
    private final Long max;
    private Long threshold = 1000L;

    public SumForkJoinTask(Long min, Long max) { 
   
        this.min = min;
        this.max = max;
    }
    @Override
    protected Long compute() { 
   
        // 小于阈值时直接计算
        if ((max - min) <= threshold) { 
   
            long sum = 0;
            for (long i = min; i < max; i++) { 
   
                sum = sum + i;
            }
            return sum;
        }
        // 拆分成小任务
        long middle = (max + min) >>> 1;
        SumForkJoinTask leftTask = new SumForkJoinTask(min, middle);
        leftTask.fork();
        SumForkJoinTask rightTask = new SumForkJoinTask(middle, max);
        rightTask.fork();
        // 汇总结果
        return leftTask.join() + rightTask.join();
    }
}

上述代码逻辑可通过下图更加直观的理解。

ForkJoin看这篇就够了![通俗易懂]

ForkJoin框架实现

在ForkJoin框架中重要的一些接口和类如下图所示。

ForkJoin看这篇就够了![通俗易懂]

ForkJoinPool

ForkJoinPool是用于运行ForkJoinTasks的线程池,实现了Executor接口。

可以通过new ForkJoinPool()直接创建ForkJoinPool对象。

public ForkJoinPool() { 
   
    this(Math.min(MAX_CAP, Runtime.getRuntime().availableProcessors()),
         defaultForkJoinWorkerThreadFactory, null, false);
}

public ForkJoinPool(int parallelism,
                        ForkJoinWorkerThreadFactory factory,
                        UncaughtExceptionHandler handler,
                        boolean asyncMode){ 
   
    this(checkParallelism(parallelism),
             checkFactory(factory),
             handler,
             asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
             "ForkJoinPool-" + nextPoolId() + "-worker-");
        checkPermission();
}

通过查看构造方法源码我们可以发现,在创建ForkJoinPool时,有以下4个参数:

  • parallelism:期望并发数。默认会使用Runtime.getRuntime().availableProcessors()的值
  • factory:创建ForkJoin工作线程的工厂,默认为defaultForkJoinWorkerThreadFactory
  • handler:执行任务时遇到不可恢复的错误时的处理程序,默认为null
  • asyncMode:工作线程获取任务使用FIFO模式还是LIFO模式,默认为LIFO

ForkJoinTask

ForkJoinTask是一个对于在ForkJoinPool中运行任务的抽象类定义。

可以通过少量的线程处理大量任务和子任务,ForkJoinTask实现了Future接口。主要通过fork()方法安排异步任务执行,通过join()方法等待任务执行的结果。

想要使用ForkJoinTask通过少量的线程处理大量任务,需要接受一些限制。

  • 拆分的任务中避免同步方法或同步代码块;
  • 在细分的任务中避免执行阻塞I/O操作,理想情况下基于完全独立于其他正在运行的任务访问的变量;
  • 不允许在细分任务中抛出受检异常。

因为ForkJoinTask是抽象类不能被实例化,所以在使用时JDK为我们提供了三种特定类型的ForkJoinTask父类供我们自定义时继承使用。

  • RecursiveAction:子任务不返回结果
  • RecursiveTask:子任务返回结果
  • CountedCompleter:在任务完成执行后会触发执行

ForkJoinWorkerThread

ForkJoinPool中用于执行ForkJoinTask的线程。

ForkJoinPool既然实现了Executor接口,那么它和我们常用的ThreadPoolExecutor之前又有什么差异呢?

如果们使用ThreadPoolExecutor来完成分治法的逻辑,那么每个子任务都需要创建一个线程,当子任务的数量很大的情况下,可能会达到上万个,那么使用ThreadPoolExecutor创建出上万个线程,这显然是不可行、不合理的;

ForkJoinPool在处理任务时,并不会按照任务开启线程,只会按照指定的期望并行数量创建线程。在每个线程工作时,如果需要继续拆分子任务,则会将当前任务放入ForkJoinWorkerThread的任务队列中,递归处理直到最外层的任务。

工作窃取算法

ForkJoinPool的各个工作线程都会维护一个各自的任务队列,减少线程之间对于任务的竞争;

每个线程都会先保证将自己队列中的任务执行完,当自己的任务执行完之后,会去看其他线程的任务队列中是否有未处理完的任务,如果有则会帮助其他线程执行;

为了减少在帮助其他线程执行任务时发生竞争,会使用双端队列来存放任务,被窃取的任务只会从队列的头部获取任务,而正常处理的线程每次都是从队列的尾部获取任务。

ForkJoin看这篇就够了![通俗易懂]

优点

充分利用了线程资源,避免资源的浪费,并且减少了线程间的竞争。

缺点

需要给每个线程开辟一个队列空间;在工作队列中只有一个任务时同样会存在线程竞争。

最后

如果觉得文章对你有点帮助,不妨点个关注。我是小黑,下期见~

ForkJoin看这篇就够了![通俗易懂]

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/191605.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Python 实现异步调用函数

    Python 实现异步调用函数async_call.py#coding:utf-8fromthreadingimportThreaddefasync_call(fn):defwrapper(*args,**kwargs):Thread(target=fn,args=args,kwargs=kwargs).start()returnwrappertest.p…

    2022年7月11日
    22
  • java中获取文件的服务器路径

    java中获取文件的服务器路径//获取文件的服务器路径importjavax.servlet.ServletContext;importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.Ht…

    2022年7月27日
    19
  • mongodb 集合_mongodb原理

    mongodb 集合_mongodb原理最近公司用MongoDB,整合一下网上的优缺点,学习下MongoDB没有找到原作者一:MongoDB的优点和缺点优点面向文档存储(类JSON数据模式简单而强大) 动态查询 全索引支持,扩展到内部对象和内嵌数组 查询记录分析 快速,就地更新 高效存储二进制大对象(比如照片和视频) 复制和故障切换支持 Auto-Sh…

    2025年6月26日
    5
  • java中打印数组的方法_Java数组方法–如何在Java中打印数组

    java中打印数组的方法_Java数组方法–如何在Java中打印数组java中打印数组的方法Anarrayisadatastructureusedtostoredataofthesametype.Arraysstoretheirelementsincontiguousmemorylocations.数组是用于存储相同类型数据的数据结构。数组将其元素存储在连续的内存位置中。InJava,arraysareo…

    2022年6月3日
    34
  • futex简介_fut是什么牌子

    futex简介_fut是什么牌子找到一篇很好的文章,讲得深入浅出;貌似原网站也很不错。转载自http://linuxperf.com/?p=23futex(fastuserspacemutex)是Linux的一个基础构件,可以用来构建各种更高级别的同步机制,比如锁或者信号量等等,POSIX信号量就是基于futex构建的。大多数时候编写应用程序并不需要直接使用futex,一般用基于它所实现的系统库就够了。futex的性能非常优异,它是怎样做到的呢?这要从它的设计思想谈起。传统的SystemVIPC(interproces

    2022年9月21日
    2
  • Python解决求最大公约数和最小公倍数问题

    Python解决求最大公约数和最小公倍数问题目录一.思路分析1.欧几里得法(辗转相除法)2.穷举法(一个一个除)3.stein算法二.提高要求三.测试截图题目:求两个正整数的最大公约数和最小公倍数。基本要求:1.程序风格良好(使用自定义注释模板),两种以上算法解决最大公约数问题,提供友好的输入输出。提高要求:1.三种以上算法解决两个正整数最大公约数问题。         2.求3个正…

    2022年5月16日
    40

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号