2015-05-11 57 views
-1

我有這個程序通過線程排序文件的數組。 這裏是我的Sort類:排序java中的線程中的文件

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(); 
      } 
     } 

    } 
} 

這裏是歸併排序類:

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; 

    } 

} 

,這裏是我的測試類:

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."); 

    } 

} 

我已經實現了使用執行人的threadedSort方法服務,但我不知道爲什麼我geting這個例外:

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) 

我搞不​​清楚我做錯了什麼請檢閱。 任何幫助將appriciated。由於

回答

1

你是從你的線程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; 
     } 
    } 

現在,您可以創建任務提交到ExecutorService並獲得Future<String[]>結果。

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; 
    } 

另外5s是一個小時間IMO。你可以提供1天的時間,如果它在這之前完成,你會得到結果,否則它會拋出超時異常。

我提出了一些改變,至少可以爲您提供正確的方向。您可以進一步探索改進代碼的各種方法。例如合併兩個數組可能會很昂貴,您可以考慮更好的選項。

+0

將使用線程和回調喜歡你會更有效率,然後簡單的排序方法(沒有線程)? –

+0

@SubhanAhmed OP正在使用'Runnable',因爲他應該使用'Callable',因爲他期望他的任務結果。我向他建議了一些屬於標準Java實踐的變化。這是否比簡單排序更有效,OP需要根據他的要求來決定。 –

+0

請解釋此評論://合併值和finalData來創建一個數組。 finalData是什麼? –

0

有幾個問題。


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

這將錯過最後文件。


對於每一個文件,你

executor.submit(worker); 

然後創建一個新的Callable從工人獲取排序的數據並返回給你(你爲什麼會想這樣做?)。

然後您等待Callable完成(爲什麼要這麼做?)。

然後關閉Executor(爲什麼要這麼做?)。

然後,您將轉到下一個文件,對於每個文件(您爲什麼要這麼做?)。


可能更多,但我失去了生活的意志。將所有這些問題排序並讓我們知道問題是否仍然存在。

+0

然後做什麼更好更高效的方法? –

+0

爲什麼它會錯過最後一個文件。 (是的,它缺少它) 是什麼原因,我該怎麼做才能避免它? –

+0

@SubhanAhmed - 'for(int i = 0; i OldCurmudgeon