在java中的线程中对文件进行排序

时间:2022-01-07 07:52:23

I have this program to sort the array of files via threads. Here is my Sort class:

我有这个程序通过线程对文件数组进行排序。这是我的Sort类:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class Sort {

    /**
     * You are to implement this method. The method should invoke one or more
     * threads to read and sort the data from the collection of Files. The
     * method should return a sorted list of all of the String data contained in
     * the files.
     * 
     * @param files
     * @return
     * @throws IOException
     */
    public static String[] threadedSort(File[] files) throws IOException {
        ExecutorService executor = Executors.newFixedThreadPool(files.length);
        Future<String[]> value = null;
        String[] sortedData = null;
        try {
            for (int i=0; i<files.length-1; i++) {
                final SortingThread worker = new SortingThread(files[i]);
                executor.submit(worker);
                value = executor.submit(new Callable<String[]>() {
                    @Override
                    public String[] call() {
                        return worker.getSortedData();
                    }
                });


            sortedData = value.get();
            executor.shutdown();
            executor.awaitTermination(5, TimeUnit.SECONDS);

        }
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < sortedData.length-1; i++) {
            System.out.println(sortedData[i]);
        }
        return sortedData;
    }

    /**
     * Given an array of files, this method will return a sorted list of the
     * String data contained in each of the files.
     * 
     * @param files
     *            the files to be read
     * @return the sorted data
     * @throws IOException
     *             thrown if any errors occur reading the file
     */
    public static String[] sort(File[] files) throws IOException {

        String[] sortedData = new String[0];

        for (File file : files) {
            String[] data = getData(file);
            data = MergeSort.mergeSort(data);
            sortedData = MergeSort.merge(sortedData, data);
        }

        return sortedData;

    }

    /**
     * This method will read in the string data from the specified file and
     * return the data as an array of String objects.
     * 
     * @param file
     *            the file containing the String data
     * @return String array containing the String data
     * @throws IOException
     *             thrown if any errors occur reading the file
     */
    private static String[] getData(File file) throws IOException {

        ArrayList<String> data = new ArrayList<String>();
        BufferedReader in = new BufferedReader(new FileReader(file));

        // Read the data from the file until the end of file is reached
        while (true) {
            String line = in.readLine();
            if (line == null) {
                // the end of file was reached
                break;
            } else {
                data.add(line);
            }
        }

        // Close the input stream and return the data
        in.close();
        return data.toArray(new String[0]);

    }

    static class SortingThread implements Runnable {

        private File file;
        private String[] sortedData = new String[0];

        public SortingThread(File file) {
            this.file = file;
        }

        public String[] getSortedData() {
            return sortedData;
        }

        @Override
        public void run() {
            try {
                String[] data = getData(file);
                data = MergeSort.mergeSort(data);
                sortedData = MergeSort.merge(sortedData, data);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

Here is the Merge Sort class:

这是Merge Sort类:

public class MergeSort {

  // The mergeSort method returns a sorted copy of the
  // String objects contained in the String array data.
  /**
   * Sorts the String objects using the merge sort algorithm.
   * 
   * @param data the String objects to be sorted
   * @return the String objects sorted in ascending order
   */
  public static String[] mergeSort(String[] data) {

    if (data.length > 1) {
      String[] left = new String[data.length / 2];
      String[] right = new String[data.length - left.length];
      System.arraycopy(data, 0, left, 0, left.length);
      System.arraycopy(data, left.length, right, 0, right.length);

      left = mergeSort(left);
      right = mergeSort(right);

      return merge(left, right);

    }
    else {
      return data;
    }

  }

  /**
   * The merge method accepts two String arrays that are assumed
   * to be sorted in ascending order. The method will return a
   * sorted array of String objects containing all String objects
   * from the two input collections.
   * 
   * @param left a sorted collection of String objects
   * @param right a sorted collection of String objects
   * @return a sorted collection of String objects
   */
  public static String[] merge(String[] left, String[] right) {

    String[] data = new String[left.length + right.length];

    int lIndex = 0;
    int rIndex = 0;

    for (int i=0; i<data.length; i++) {
      if (lIndex == left.length) {
        data[i] = right[rIndex];
        rIndex++;
      }
      else if (rIndex == right.length) {
        data[i] = left[lIndex];
        lIndex++;
      }
      else if (left[lIndex].compareTo(right[rIndex]) < 0) {
        data[i] = left[lIndex];
        lIndex++;
      }
      else {
        data[i] = right[rIndex];
        rIndex++;
      }
    }

    return data;

  }

}

And here is my test class:

这是我的测试类:

import java.io.File;
import java.io.IOException;

/**
 * The class SortTest is used to test the threaded and non-threaded sort
 * methods. This program will call each method to sort the data contained in the
 * four test files. This program will then test the results to ensure that the
 * results are sorted in ascending order.
 * 
 * Simply run this program to verify that you have correctly implemented the
 * threaded sort method. The program will not verify if your sort uses threads,
 * but will verify if your implementation correctly sorted the data contained in
 * the four files.
 * 
 * There should be no reason to make modifications to this class.
 */
public class SortTest {

    public static void main(String[] args) throws IOException,
            IllegalStateException {

        File[] files = { new File("res/file1.txt"), new File("res/file2.txt") };

        // Run Sort.sort on the files
        long startTime = System.nanoTime();
        String[] sortedData = Sort.sort(files);
        long stopTime = System.nanoTime();
        double elapsedTime = (stopTime - startTime) / 1000000000.0;

        // Test to ensure the data is sorted
        for (int i = 0; i < sortedData.length - 1; i++) {
            if (sortedData[i].compareTo(sortedData[i + 1]) > 0) {
                System.out
                        .println("The data returned by Sort.sort is not sorted.");
                throw new java.lang.IllegalStateException(
                        "The data returned by Sort.sort is not sorted");
            }
        }
        System.out.println("The data returned by Sort.sort is sorted.");
        System.out.println("Sort.sort took " + elapsedTime
                + " seconds to read and sort the data.");

        // Run Sort.threadedSort on the files and test to ensure the data is
        // sorted
        startTime = System.nanoTime();
        String[] threadSortedData = Sort.threadedSort(files);
        stopTime = System.nanoTime();
        double threadedElapsedTime = (stopTime - startTime) / 1000000000.0;

        // Test to ensure the data is sorted
        if (sortedData.length != threadSortedData.length) {
            System.out
                    .println("The data return by Sort.threadedSort is missing data");
            throw new java.lang.IllegalStateException(
                    "The data returned by Sort.threadedSort is not sorted");
        }
        for (int i = 0; i < threadSortedData.length - 1; i++) {
            if (threadSortedData[i].compareTo(threadSortedData[i + 1]) > 0) {
                System.out
                        .println("The data return by Sort.threadedSort is not sorted");
                throw new java.lang.IllegalStateException(
                        "The data returned by Sort.threadedSort is not sorted");
            }
        }
        System.out.println("The data returned by Sort.threadedSort is sorted.");
        System.out.println("Sort.threadedSort took " + threadedElapsedTime
                + " seconds to read and sort the data.");

    }

}

I have implemented the threadedSort method using executor Services but i don't know why i'm geting this exception:

我已经使用executor Services实现了threadedSort方法,但我不知道为什么我要解决这个异常:

The data returned by Sort.sort is sorted.
Sort.sort took 0.003480673 seconds to read and sort the data.
The data return by Sort.threadedSort is missing data
Exception in thread "main" java.lang.IllegalStateException: The data returned by Sort.threadedSort is not sorted
    at com.teamincredibles.threading.SortTest.main(SortTest.java:56)

I can't figure out what i've done wrong please review. Any help would be appriciated. Thanks

我无法弄清楚我做错了什么,请复习。任何帮助都会得到满足。谢谢

2 个解决方案

#1


1  

You are expecting result from your thread SortingThread so you should use Callable and not Runnable as:

您期望线程SortingThread的结果,因此您应该使用Callable而不是Runnable:

        static class SortingThread implements Callable<String[]> {

        private File file;
        private String[] sortedData = new String[0];

        public SortingThread(File file) {
            this.file = file;
        }

        public String[] getSortedData() {
            return sortedData;
        }

        @Override
        public String[] call() throws Exception {
            String[] data = getData(file);
            data = MergeSort.mergeSort(data);
            sortedData = MergeSort.merge(sortedData, data);
            return sortedData;
        }
    }

Now you can create tasks to submit to ExecutorService and get Future<String[]> as a result.

现在,您可以创建要提交给ExecutorService的任务,并获取Future 作为结果。

public static String[] threadedSort(File[] files) throws IOException, InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newFixedThreadPool(files.length);
        List<Future<String[]>> futureList = new ArrayList<>();
        String[] sortedData = null;
        for (int i=0; i<files.length; i++) {
            futureList.add(executor.submit(new SortingThread(files[i])));
        }
        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.DAYS);

        for (Future<String[]> future :futureList) {
        String[] values = future.get();
        // merge values and  finalData to create one array.
      }
      return finalData;
    }

Also 5s is a small time IMO. You can provide time of 1 day and if it finishes before that you will get the result else it will throw timeout exception.

5s也是一个小时间的IMO。您可以提供1天的时间,如果它在此之前完成,您将获得结果,否则它将抛出超时异常。

I have suggested some changes which can at least provide you right direction. You can further explore various ways to improve your code. For example merging two arrays may be expensive and you can think about better option.

我已经提出了一些改变,至少可以为你提供正确的方向。您可以进一步探索改进代码的各种方法。例如,合并两个数组可能很昂贵,您可以考虑更好的选择。

#2


0  

Several issues.


for (int i=0; i<files.length-1; i++)

This will miss the last file.

这将错过最后一个文件。


For each file you

对于你的每个文件

executor.submit(worker);

you then create a new Callable that gets the sorted data from the worker and returns it to you (why would you want to do that?).

然后创建一个新的Callable,从工作者获取已排序的数据并将其返回给您(为什么要这样做?)。

You then wait for that Callable to finish (why would you want to do that?).

然后等待Callable完成(你为什么要这样做?)。

You then shut down the Executor (why would you want to do that?).

然后关闭执行程序(为什么要这样做?)。

You then move on to the next file all this for each file (why would you want to do that?).

然后,为每个文件移动到下一个文件(为什么要这样做?)。


Probably more but I am losing the will to live. Get all of those issues sorted and let us know if the problem still remains.

可能更多,但我失去了生活的意志。将所有这些问题排序并告知我们问题是否仍然存在。

#1


1  

You are expecting result from your thread SortingThread so you should use Callable and not Runnable as:

您期望线程SortingThread的结果,因此您应该使用Callable而不是Runnable:

        static class SortingThread implements Callable<String[]> {

        private File file;
        private String[] sortedData = new String[0];

        public SortingThread(File file) {
            this.file = file;
        }

        public String[] getSortedData() {
            return sortedData;
        }

        @Override
        public String[] call() throws Exception {
            String[] data = getData(file);
            data = MergeSort.mergeSort(data);
            sortedData = MergeSort.merge(sortedData, data);
            return sortedData;
        }
    }

Now you can create tasks to submit to ExecutorService and get Future<String[]> as a result.

现在,您可以创建要提交给ExecutorService的任务,并获取Future 作为结果。

public static String[] threadedSort(File[] files) throws IOException, InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newFixedThreadPool(files.length);
        List<Future<String[]>> futureList = new ArrayList<>();
        String[] sortedData = null;
        for (int i=0; i<files.length; i++) {
            futureList.add(executor.submit(new SortingThread(files[i])));
        }
        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.DAYS);

        for (Future<String[]> future :futureList) {
        String[] values = future.get();
        // merge values and  finalData to create one array.
      }
      return finalData;
    }

Also 5s is a small time IMO. You can provide time of 1 day and if it finishes before that you will get the result else it will throw timeout exception.

5s也是一个小时间的IMO。您可以提供1天的时间,如果它在此之前完成,您将获得结果,否则它将抛出超时异常。

I have suggested some changes which can at least provide you right direction. You can further explore various ways to improve your code. For example merging two arrays may be expensive and you can think about better option.

我已经提出了一些改变,至少可以为你提供正确的方向。您可以进一步探索改进代码的各种方法。例如,合并两个数组可能很昂贵,您可以考虑更好的选择。

#2


0  

Several issues.


for (int i=0; i<files.length-1; i++)

This will miss the last file.

这将错过最后一个文件。


For each file you

对于你的每个文件

executor.submit(worker);

you then create a new Callable that gets the sorted data from the worker and returns it to you (why would you want to do that?).

然后创建一个新的Callable,从工作者获取已排序的数据并将其返回给您(为什么要这样做?)。

You then wait for that Callable to finish (why would you want to do that?).

然后等待Callable完成(你为什么要这样做?)。

You then shut down the Executor (why would you want to do that?).

然后关闭执行程序(为什么要这样做?)。

You then move on to the next file all this for each file (why would you want to do that?).

然后,为每个文件移动到下一个文件(为什么要这样做?)。


Probably more but I am losing the will to live. Get all of those issues sorted and let us know if the problem still remains.

可能更多,但我失去了生活的意志。将所有这些问题排序并告知我们问题是否仍然存在。