单线程排序和利用Fork/Join进行多线程并行排序的简单对比

Fork/Join框架自从在JDK7中引进之后,对并行计算的设计带来了更多便利。

本文使用java原生的排序方法Array.sort单线程排序,和利用Fork/Join框架进行任务分割设计的快速排序进行对比。

首先,使用以下方法构造一个简单的文件样本,目标是生成一个文本文件,10000000行,每行为一个20000以内的随机数:

package sort;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Random;

public class GenerateSample {
	public static void main(String[] args) {
		File f = new File("/home/nox/java/sort/sample.txt");
		FileWriter writer;
		try {
			writer = new FileWriter(f, false);

			Random random1 = new Random(10);

			for (int i = 0; i < 10000000; i++) {
				writer.write(String.valueOf(random1.nextInt(20000)));
				writer.write("\r\n");
			}

			writer.close();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {

		}
	}
}

运行之后,可以看到文件信息的片段如下:

168890149 Aug  9 21:59 sample.txt

可以看到该文件的大小为168MB左右,可能根据操作系统的不同略有差异。

然后,我们将使用下面的普通排序方式对该文件里面的数据进行排序然后输出,因为本文的目标仅仅是简单的测算排序的速度,所以对IO并没有进行任何优化,仅仅是将文件里面的数据进行读取然后排序。故下面的代码也只对排序过程所耗费的时间进行计算。代码如下:

package sort;

import java.io.BufferedReader;

import java.io.File;
import java.io.FileWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ArraySort {
        public static void main(String args[]) {
                File f = new File("/home/nox/java/sort/sample.txt");
                List arrayList = new ArrayList();
                try {
                        BufferedReader reader = new BufferedReader(new FileReader(f));

                        String str = null;
                        while ((str = reader.readLine()) != null) {
                                arrayList.add(Integer.valueOf(str));
                        }
                } catch (FileNotFoundException e) {
                        e.printStackTrace();
                } catch (IOException e) {
                        e.printStackTrace();
                }

                long startTime=System.currentTimeMillis();
                Collections.sort(arrayList);
                long endTime=System.currentTimeMillis();

                System.out.println("排序所花时间:"+(endTime-startTime)+"ms");

                File f2 = new File("/home/nox/java/sort/original_sorted.txt");
                FileWriter writer2;
                try {
                        writer2 = new FileWriter(f2, false);

                        for (int i = 0; i < arrayList.size(); i++) {
                                writer2.write(String.valueOf(arrayList.get(i)));
                                writer2.write("\r\n");
                        }

                        writer2.close();
                } catch (IOException e) {
                        e.printStackTrace();
                } finally {

                }
        }
}

输出结果为:

排序所花时间:16259ms

可以看到排序话费的时间为16259ms,说明一下, 此处运行程序并没有对JVM参数进行任何调整,只是简单测试运行的结果,所以在不同的计算机硬件配置和不同的操作系统下,可能会有偏差。

然后,我们使用基于 Fork/Join 框架的多线程并行化设计的快速排序进行排序。看看所耗费的时间如何。代码如下:

package sort;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.RecursiveTask;

public class FastSortByForkAndJoin {
	public static void main(String args[]) {
		File f = new File("/home/nox/java/sort/sample.txt");
        List arrayList = new ArrayList();
        try {
                BufferedReader reader = new BufferedReader(new FileReader(f));

                String str = null;
                while ((str = reader.readLine()) != null) {
                        arrayList.add(Integer.valueOf(str));
                }
        } catch (FileNotFoundException e) {
                e.printStackTrace();
        } catch (IOException e) {
                e.printStackTrace();
        }

        long longArray[] = new long[arrayList.size()];
        for( int i =0;i<arrayList.size();i++){
        	longArray[i] = Long.parseLong(arrayList.get(i).toString());
        }

		ForkJoinPool pool = new ForkJoinPool();

		FastSort fastSort = new FastSort(longArray);

		long startTime=System.currentTimeMillis();
		pool.execute(fastSort);
		while(!fastSort.isDone()){

		}

		long endTime=System.currentTimeMillis();

        System.out.println("排序所花时间:"+(endTime-startTime)+"ms");
        File f2 = new File("/home/nox/java/sort/fastSorted.txt");

        FileWriter writer2;
        try {
                writer2 = new FileWriter(f2, false);

                for (int i = 0; i < longArray.length; i++) {
                        writer2.write(String.valueOf(longArray[i]));
                        writer2.write("\r\n");
                }

                writer2.close();
        } catch (IOException e) {
                e.printStackTrace();
        } finally {

        }

	}

}

class FastSort extends RecursiveAction {

	 final long[] array;
	    final int lo;
	    final int hi;
	    private int THRESHOLD = 30;

	    public FastSort(long[] array) {
	        this.array = array;
	        this.lo = 0;
	        this.hi = array.length - 1;
	    }

	    public FastSort(long[] array, int lo, int hi) {
	        this.array = array;
	        this.lo = lo;
	        this.hi = hi;
	    }

	    protected void compute() {
	        if (hi - lo < THRESHOLD)
	            sequentiallySort(array, lo, hi);
	        else {
	            int pivot = partition(array, lo, hi);
	            FastSort left = new FastSort(array, lo, pivot - 1);
	            FastSort right = new FastSort(array, pivot + 1, hi);

				invokeAll(left, right);
	        }
	    }

	    private int partition(long[] array, int lo, int hi) {
	        long x = array[hi];
	        int i = lo - 1;
	        for (int j = lo; j < hi; j++) {
	            if (array[j] <= x) {
	                i++;
	                swap(array, i, j);
	            }
	        }
	        swap(array, i + 1, hi);
	        return i + 1;
	    }

	    private void swap(long[] array, int i, int j) {
	        if (i != j) {
	            long temp = array[i];
	            array[i] = array[j];
	            array[j] = temp;
	        }
	    }

	    private void sequentiallySort(long[] array, int lo, int hi) {
	        Arrays.sort(array, lo, hi + 1);
	    }
}

输出结果为:

 排序所花时间:2212ms

可以看到,排序时间比之前的方式要少很多。

总结:在多线程方式下,尽管我们没有对JVM参数,线程数量和单任务中的阀值进行更多的优化,仅仅是一个简单的多线程快速排序,在速度上就已经原胜普通的排序方式,相信如果在数据样本更大的情况下,进行更多的优化,排序的速度势必会有更大的差异。

时间: 2024-10-11 04:44:41

单线程排序和利用Fork/Join进行多线程并行排序的简单对比的相关文章

JAVA中的Fork/Join框架

看了下Java Tutorials中的fork/join章节,整理下. 什么是fork/join框架 fork/join框架是ExecutorService接口的一个实现,可以帮助开发人员充分利用多核处理器的优势,编写出并行执行的程序,提高应用程序的性能:设计的目的是为了处理那些可以被递归拆分的任务. fork/join框架与其它ExecutorService的实现类相似,会给线程池中的线程分发任务,不同之处在于它使用了工作窃取算法,所谓工作窃取,指的是对那些处理完自身任务的线程,会从其它线程窃

Fork/Join框架介绍(转)

1. 什么是Fork/Join框架 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架. 我们再通过Fork和Join这两个单词来理解下Fork/Join框架,Fork就是把一个大任务切分为若干子任务并行的执行,Join就是合并这些子任务的执行结果,最后得到这个大任务的结果.比如计算1+2+..+10000,可以分割成10个子任务,每个子任务分别对1000个数进行求和,最终汇总这10个子任务的结果

聊聊并发(八)——Fork/Join框架介绍

作者 方腾飞 发布于 2013年12月23日 | 被首富的“一个亿”刷屏?不如定个小目标,先把握住QCon上海的优惠吧!2 讨论 分享到:微博微信FacebookTwitter有道云笔记邮件分享 稍后阅读 我的阅读清单 1. 什么是Fork/Join框架 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架. 我们再通过Fork和Join这两个单词来理解下Fork/Join框架,Fork就是把一个大

Fork/Join框架介绍

转http://www.infoq.com/cn/articles/fork-join-introduction/ 1. 什么是Fork/Join框架 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架. 我们再通过Fork和Join这两个单词来理解下Fork/Join框架,Fork就是把一个大任务切分为若干子任务并行的执行,Join就是合并这些子任务的执行结果,最后得到这个大任务的结果.比如计算

Java 多线程 Fork/Join

Fork/Join Fork/Join将大任务切分成小任务来分治运算,fork分join合. 一般直接使用ForkJoinTask的子类RecursiveTask. RecursiveTask的用法 1.新建类A来继承RecursiveTask,实现compute()方法,这个方法就是需要分治的代码.其中,调用fork()方法来表示需要分解计算的内容,调用join()方法来获取结果 2.新建ForkJoinPool,使用ForkJoinPool.submit(A的实例),来提交分治代码,并使用F

Java多线程之~~~Fork/Join框架的同步和异步

在Fork/Join框架中,提交任务的时候,有同步和异步两种方式.以前使用的invokeAll()的方法是同步的,也就是任 务提交后,这个方法不会返回直到所有的任务都处理完了.而还有另一种方式,就是使用fork方法,这个是异步的.也 就是你提交任务后,fork方法立即返回,可以继续下面的任务.这个线程也会继续运行. 下面我们以一个查询磁盘的以log结尾的文件的程序例子来说明异步的用法. package com.bird.concursey.charpet8; import java.io.Fil

Java对多线程~~~Fork/Join同步和异步帧

于Fork/Join骨架,当提交的任务,有两个同步和异步模式.它已被用于invokeAll()该方法是同步的.是任何 务提交后,这种方法不会返回直到全部的任务都处理完了.而还有还有一种方式,就是使用fork方法,这个是异步的.也 就是你提交任务后,fork方法马上返回.能够继续以下的任务. 这个线程也会继续执行. 以下我们以一个查询磁盘的以log结尾的文件的程序样例来说明异步的使用方法. package com.bird.concursey.charpet8; import java.io.Fi

多线程-Fork/Join

Fork/Join Java7提供了Fork/Join来支持将一个任务拆分成多个"小任务"并行计算,再把多个"小任务"的结果合并成总的计算结果. 类图 Java7提供了ForkJoinPool来支持将一个任务拆分为多个小任务并行计算,再把多个小任务的结果合并成总的计算结果.ForkJoinPool是ExecutorService的实现类,因此是一种特殊的线程池. ForkJoinPool(int n)创建一个包含n个并行线程的ForkJoinPool ForkJoi

线程基础:多任务处理(13)——Fork/Join框架(解决排序问题)

============== 接上文< 线程基础:多任务处理(12)--Fork/Join框架(基本使用)> 3. 使用Fork/Join解决实际问题 之前文章讲解Fork/Join框架的基本使用时,所举的的例子是使用Fork/Join框架完成1-1000的整数累加.这个示例如果只是演示Fork/Join框架的使用,那还行,但这种例子和实际工作中所面对的问题还有一定差距.本篇文章我们使用Fork/Join框架解决一个实际问题,就是高效排序的问题. 3-1. 使用归并算法解决排序问题 排序问题是