forkjoin并发分页查数据_java fork join

forkjoin并发分页查数据_java fork join分治,顾名思义,即分而治之,是一种解决复杂问题的思维方法和模式;具体来讲,指的是把一个复杂的问题分解成多个相似的子问题,然后再把子问题分解成更小的子问题,直到子问题简单到可以直接求解。Java并发包里提供了一种叫做Fork/Join的并行计算框架,就是用来支持分治这种任务模型的。如何用Fork/Join并行计算框架计算斐波那契数列f(n)=f(n-1)+f(n-…

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

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

为什么用 Fork/Join ?

对于简单的并行任务,你可以通过“线程池+Future”的方案来解决;如果任务之间有聚合关系,无论是AND聚合还是OR聚合,都可以通过CompletableFuture来解决;而批量的并行任务,则可以通过CompletionService来解决。这几种方案基本上能够覆盖日常工作中的并发场景了,但还是不够全面,因为还有一种“分治”的任务模型没有覆盖到

分治,顾名思义,即分而治之,是一种解决复杂问题的思维方法和模式;具体来讲,指的是把一个复杂的问题分解成多个相似的子问题,然后再把子问题分 解成更小的子问题,直到子问题简单到可以直接求解

forkjoin并发分页查数据_java fork join
Java并发包里提供了一种叫做Fork/Join的并行计算框架,就是用来支持分治这种任务模型的。
 

 

 

如何用Fork/Join 并行计算框架计算斐波那契数列

   f(n)=f(n-1)+f(n-2)

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
public class forkjoin {
    public static void main(String[] args) {
        //创建分治任务线程池
        ForkJoinPool fjp = new	ForkJoinPool(4);
        //创建分治任务
        Fibonacci fib = new	Fibonacci(30);
        //启动分治任务
        Long start_time = System.currentTimeMillis();
        Integer	result = fjp.invoke(fib);
        //输出结果
        Long end_time = System.currentTimeMillis();
        Long compute_time = end_time - start_time;
        System.out.println("result: "+result);
        System.out.println("forkjoin compute_time: "+ compute_time);
    }
    //递归任务
    static class Fibonacci extends RecursiveTask<Integer>{
        final	int	n;
        Fibonacci(int	n){this.n	=	n;}
        protected	Integer	compute(){
            if(n<=1) 
                return n;
            Fibonacci f1 = new Fibonacci(n-1);
            //创建⼦任务
            f1.fork();
            Fibonacci f2 = new Fibonacci(n-2);
            //等待⼦任务结果,并合并结果
            return f2.compute()+f1.join();
        }
    }
}

普通单线程计算斐波那契数列

public class fibonacci {
    public static void main(String[] args) {
        Fibonacci fib = new	Fibonacci(30);
        Long start_time = System.currentTimeMillis();
        Integer	result = fib.compute();
        Long end_time = System.currentTimeMillis();
        Long compute_time = end_time - start_time;
        System.out.println("result: "+result);
        System.out.println("compute_time: "+ compute_time);
    }
    //递归任务
    static class Fibonacci {
        final int n;
        Fibonacci(int n){
            this.n = n;
        }
        protected	Integer	compute(){
            //终止条件
            if(n<=1)
                return	n;
            //创建⼦任务
            Fibonacci f1 = new	Fibonacci(n-1);
            Fibonacci f2 = new	Fibonacci(n-2);
            //等待⼦任务结果,并合并结果
            return f2.compute()+f1.compute();
        }
    }
}

分别执行,会发现普通计算的方式会更快,说明forkjoin在调度方面会有很大的性能消耗。

在终止条件下加上一条休眠语句,使每次计算都要持续设定时间以上,再对比两种方式的速度。

 Fibonacci fib = new	Fibonacci(5);

 //终止条件
if(n<=1) {
    if(n<=1) {
         try {
              Thread.sleep(1000);
         }catch (Exception e){
              e.printStackTrace();
         }
         return n;
     }
}

可以发现并行的计算方式的执行速度,与设定的的线程数量有关,比如第五个斐波那契数列的值,需要分解为8次计算任务,每次至少需要8秒。普通计算方式需要8秒,并行计算方式在线程数为4的情况下,执行时间为2秒;线程数为8的情况下,执行时间为1秒。实际执行速度应与CPU的核数有关,即如果CPU只有4核,就算设置为8线程,最快速度也只有2秒(示例中执行时间为1秒是因为采用线程休眠来模拟该线程的总处理时间,实际该线程在休眠期间并不消耗计算资源)

 

使用Fork/Join需要注意的地方

在使用Fork/Join时,需要注意出现工作线程不工作的事情。下面从不同的使用方式来分析: fork() 和 compute()

  在示例中,下面这句语句是分解任务以及合并任务的关键

 f1.fork();
//等待⼦任务结果,并合并结果
return f2.compute()+f1.join();

 主线程分配了一个任务给子线程,同时自己也执行一次计算任务。

方式1: a.fork(); b.fork(); b.join(); a.join();

f1.fork();
f2.fork();
return f2.join()+f1.join();

  这种使用方式内部做了很多优化,目的都是为了避免出现工作线程只分配任务而不执行任务的情况。

方式2:invokeAll(a,b)

invokeAll(f1, f2);
return f2.join()+f1.join();

    invokeAll的N个任务中,其中N-1个任务会使用fork()交给其它线程执行,但是,它还会留一个任务自己执行,这样,就充分利用了线程池,保证没有空闲的不干活的线程。 

方式3:a.fork(); b.fork(); a.join(); b.join();    (错误的使用方式,不建议使用

f1.fork();
f2.fork();
return f1.join()+f2.join();

       这种使用方式会出现工作线程只分配任务给子线程,自己却不执行任务的情况。比如某个任务可以分为四个子任务,线程a把任务分给线程b线程c,而线程b线程c又继续分给自己的子线程(b分解为b1和b2 / c分解为c1和c2),总共需要7个线程,但是abc却不参与计算。而第一种使用方法,Java内部做了优化。

总结

用两次fork()在join的时候,需要用这样的顺序:a.fork(); b.fork(); b.join(); a.join();这个要求在JDK官方文档里有说明。

建议使用fork() 和 compute() ,这样可以避免避免性能问题,且更容易理解。该用法可理解为在主线程中使用fork分解一次任务,同时该线程执行一次compute 计算,如果该compute计算还需要分解任务,则继续fork() 和 compute(),直到满足终止条件直接返回。因此主线程会不断分解任务,直到任务无法分解并计算该任务返回计算结果。即主线程的处理任务是分解n/2 次任务以及执行一次无法分解的任务。

 

参考 :

https://www.liaoxuefeng.com/article/001493522711597674607c7f4f346628a76145477e2ff82000 

https://time.geekbang.org/discuss/detail/90130/

forkjoin并发分页查数据_java fork join

 

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

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

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


相关推荐

  • oracle number类型的数值存储空间是几个字节?

    oracle number类型的数值存储空间是几个字节?其实有公式可以计算:number(p,s)占用得空间为:length=floor((p+1)/2)+1备注:如果该数值为负数,需要再加一个字节。—————-例如:NUMBER(14,4)的类型数值,存储空间为selectfloor((14+1)/2)+1fromdual结果输出为:8

    2022年7月24日
    7
  • pycharm2021专业版激活码【注册码】

    pycharm2021专业版激活码【注册码】,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月18日
    52
  • mysql的命名规则_Mysql命名规范

    mysql的命名规则_Mysql命名规范转自:https://blog.csdn.net/fujian9544/article/details/86649096数据库表字段命名规范内容由网上摘抄并进行总结/精简/标记后的内容本文包含了数据库命名数据库表命名数据库表字段命名SQL语言编码的规范一、数据库命名规范采用26个英文字母(区分大小写)和0-9的自然数(经常不需要)加上下划线’_’组成,命名简洁明确,多个单词用下划线’_’分隔,一个…

    2022年7月14日
    14
  • python接口自动化实战(框架)

    python接口自动化实战(框架)    python接口测试的原理,就不解释了,百度一大堆。   先看目录,可能这个框架比较简单,但是麻雀虽小五脏俱全。各个文件夹下的文件如下:一.理清思路   我这个自动化框架要实现什么   1.从excel里面提取测试用例   2.测试报告的输出,并且测试报告得包括执行的测试用例的数量、成功的数量、失败的数量以及哪条成功了,失败的是哪一个,失败的原因是什么;测试结果的总体情况通过图表…

    2025年5月28日
    3
  • Java 并发编程中的死锁 ( Kotlin 语言讲解)

    Java 并发编程中的死锁 ( Kotlin 语言讲解)什么是死锁?在操作系统中的并发处理场景中,进程对资源的持有与请求过程中,会产生死锁.Say,ProcessAhasresourceR1,ProcessBhasresourceR2.IfProcessArequestresourceR2andProcessBrequestsresourceR1,atthesametime,thend…

    2022年7月16日
    15
  • oracle数据库的字符串拼接符号_oracle将数字转换成字符串

    oracle数据库的字符串拼接符号_oracle将数字转换成字符串现在有一个需求:把字符串中代表日的截取出来,如果小于10就前面拼接一个0;如果大于等于10就不拼接。这里不说怎么截取字符串,怎么判断,主要说拼接字符串。oracle拼接字符串用||,字符串也可以和数字拼接。假设现在截取出来的日是3,那么应该是03,下面的sql没有问题:select0||3fromstudent;…

    2022年9月15日
    2

发表回复

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

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