java分治思想之ForkJoin怎么应用


本文小编为大家详细介绍“java分治思想之ForkJoin怎么应用”,内容详细,步骤清晰,细节处理妥当,希望这篇“java分治思想之ForkJoin怎么应用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

分治思想算法

fork-join模式是基于分治思想的并行计算模式之一。该模式将一个大的任务分割成多个小的子任务,然后并行执行这些子任务,最后将它们的结果合并起来得到最终的结果。在这个过程中,每个子任务的执行可以进一步分解为更小的子任务,直到达到某个阈值,这时候任务将被串行执行。这种递归的分治思想使得fork-join模式可以有效地利用计算机的多核处理能力,从而提高程序的性能和效率。

归并排序

归并排序是一种基于分治思想的排序算法。其核心思想是将一个数组分成两个子数组,分别对其进行排序后再将其合并起来。具体实现过程如下:

  • 分解:将一个数组分成两个子数组,分别对其进行排序。可以使用递归来实现这一步骤。

  • 合并:将排序后的两个子数组合并成一个有序的数组。

  • 递归:对两个子数组递归进行分解和排序,直到每个子数组的长度为1。

时间复杂度为O(nlogn)。

publicclassMerge{publicstaticvoidmain(String[]args){int[]arr={5,2,8,4,7,1,3,6};mergeSort(arr,0,arr.length-1);System.out.println(Arrays.toString(arr));}/***拆分*@paramarr数组*@paramleft数组第一个元素*@paramright数组最后一个元素*/publicstaticvoidmergeSort(int[]arr,intleft,intright){if(left<right){intmid=(left+right)/2;mergeSort(arr,left,mid);mergeSort(arr,mid+1,right);merge(arr,left,mid,right);}}/***合并*@paramarr数组*@paramleft数组第一个元素*@parammid数组分割的元素*@paramright数组最后一个元素*/publicstaticvoidmerge(int[]arr,intleft,intmid,intright){//创建临时数组,用于存放合并后的数组int[]temp=newint[right-left+1];//左面数组的起始指针inti=left;//右面数组的起始指针intj=mid+1;//临时数组的下标intk=0;//数组左面和数组右面都还有值就去遍历比较赋值while(i<=mid&&j<=right){//数组左面的值小于或者等于数组右面的值就把左面的值赋值到临时数组中//并且把左面的指针和临时数组的指针+1//否则相反if(arr[i]<=arr[j]){temp[k]=arr[i];k++;i++;}else{temp[k]=arr[j];k++;j++;}}//把剩余数组塞进去while(i<=mid){temp[k]=arr[i];k++;i++;}while(j<=right){temp[k]=arr[j];k++;j++;}//讲临时数组中的元素拷贝会回原数组中for(intp=0;p<temp.length;p++){arr[left+p]=temp[p];}}}

快速排序

快速排序(Quick Sort)是一种基于分治思想的排序算法,它采用了递归的方式将一个大的数组分解成多个子数组,分别进行排序后再将它们合并起来。其基本思想是选取一个基准元素,将数组中小于该元素的值放在左边,大于该元素的值放在右边,然后递归地对左右两个子数组进行排序。具体的步骤如下:

  • 选取一个基准元素(通常是数组中的第一个元素)。

  • 将数组中小于该元素的值放在左边,大于该元素的值放在右边。

  • 对左右两个子数组分别递归进行快速排序。

  • 合并左右两个已排序的子数组。

快速排序的时间复杂度为O(nlogn),它是一种原地排序算法,不需要额外的存储空间,因此空间复杂度为O(1)。虽然快速排序的最坏时间复杂度为O(n^2),但是在实际应用中,快速排序的平均时间复杂度和最好时间复杂度均为O(nlogn),因此是一种非常高效的排序算法

publicclassQuickSort{publicstaticvoidmain(String[]args){int[]arr={5,2,8,4,7,1,3,6};quickSort(arr,0,arr.length-1);System.out.println(Arrays.toString(arr));}publicstaticvoidquickSort(int[]arr,intleft,intright){if(left<right){intpivotIndex=partition(arr,left,right);quickSort(arr,left,pivotIndex-1);quickSort(arr,pivotIndex+1,right);}}publicstaticintpartition(int[]arr,intleft,intright){//取第一个元素为基准元素intpivot=arr[left];inti=left+1;intj=right;while(i<=j){//当前指针位置数小于基准元素就继续移动指针直到遇到大的while(i<=j&&arr[i]<pivot){i++;}//当前指针位置数大于基准元素就继续移动指针直到遇到小的while(i<=j&&arr[j]>pivot){j--;}if(i<j){//交换元素位置swap(arr,i,j);i++;j--;}}//跳出循环说明i和j相遇,j的值一定是大于基准元素,要和基准元素进行交换swap(arr,left,j);//返回基准元素位置returnj;}publicstaticvoidswap(int[]array,inti,intj){inttemp=array[i];array[i]=array[j];array[j]=temp;}}

Fork/Join

Fork/Join框架的主要组成部分是ForkJoinPool、ForkJoinTask。ForkJoinPool是一个线程池,它用于管理ForkJoin任务的执行。ForkJoinTask是一个抽象类,用于表示可以被分割成更小部分的任务。

ForkJoinPool

ForkJoinPool是Fork/Join框架中的线程池类,它用于管理Fork/Join任务的线程。ForkJoinPool类包括一些重要的方法,例如submit()、invoke()、shutdown()、awaitTermination()等,用于提交任务、执行任务、关闭线程池和等待任务的执行结果。ForkJoinPool类中还包括一些参数,例如线程池的大小、工作线程的优先级、任务队列的容量等,可以根据具体的应用场景进行设置。

构造器

ForkJoinPool中有四个核心参数,用于控制线程池的并行数、工作线程的创建、异常处理和模式指定等。

  • int parallelism:指定并行级别(parallelism level)。ForkJoinPool将根据这个设定,决定工作线程的数量。如果未设置的话,将使用Runtime.getRuntime().availableProcessors()来设置并行级别;

  • ForkJoinWorkerThreadFactory factory:ForkJoinPool在创建线程时,会通过factory来创建。注意,这里需要实现的是ForkJoinWorkerThreadFactory,而不是ThreadFactory。如果你不指定factory,那么将由默认的 DefaultForkJoinWorkerThreadFactory负责线程的创建工作;

  • UncaughtExceptionHandler handler:指定异常处理器,当任务在运行中出错时,将由设定的处理器处理;

  • boolean asyncMode:设置队列的工作模式。当asyncMode为true时,将使用先进先出队列,而为false时则使用后进先出的模式。

工作窃取法

在Fork-Join模式中,任务被分配给一个线程池中的工作线程来执行。当一个工作线程执行完自己分配的任务后,它可以从其他工作线程的任务队列中偷取(Steal)任务来执行,这就是所谓的工作窃取(Work Stealing)。

使用
publicclassSumTaskextendsRecursiveTask<Integer>{privatestaticfinalintTHRESHOLD=1000;privateint[]array;privateintstart;privateintend;publicSumTask(int[]array,intstart,intend){this.array=array;this.start=start;this.end=end;}@OverrideprotectedInteger&nbsppute(){if(end-start<=THRESHOLD){intsum=0;for(inti=start;i<end;i++){sum+=array[i];}returnsum;}else{intmid=(start+end)/2;SumTaskleftTask=newSumTask(array,start,mid);SumTaskrightTask=newSumTask(array,mid,end);leftTask.fork();rightTask.fork();intleftResult=leftTask.join();intrightResult=rightTask.join();returnleftResult+rightResult;}}publicstaticvoidmain(String[]args){int[]array=newint[10000];for(inti=0;i<array.length;i++){array[i]=i+1;}ForkJoinPoolforkJoinPool=newForkJoinPool();SumTasktask=newSumTask(array,0,array.length);intresult=forkJoinPool.invoke(task);System.out.println(result);}}

读到这里,这篇“java分治思想之ForkJoin怎么应用”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注主机评测网行业资讯频道。


上一篇:怎么去掉IntelliJ?IDEA中mybatis对应的xml文件警告

下一篇:react组件传值的方法有哪些


Copyright © 2002-2019 测速网 www.inhv.cn 皖ICP备2023010105号
测速城市 测速地区 测速街道 网速测试城市 网速测试地区 网速测试街道
温馨提示:部分文章图片数据来源与网络,仅供参考!版权归原作者所有,如有侵权请联系删除!

热门搜索 城市网站建设 地区网站制作 街道网页设计 大写数字 热点城市 热点地区 热点街道 热点时间 房贷计算器