2017-01-22 63 views
-2

我在java中自學多線程。我的虛擬示例是我有一大堆我想要排序的記錄(一個2D數組)。單線程方法是使用循環遍歷記錄列表和排序。我想用多線程程序對固定數量的線程進行排序,在這種情況下,2.一個線程將對列表的前半部分進行排序,第二個線程將對剩下的一半進行排序。然後我想輸出現在排序的記錄列表的結果。如何在java中使用多線程對記錄列表進行排序?

如何創建一個工作線程池並對記錄列表進行排序?我需要擔心data是共享資源嗎?如何將每個線程的結果返回到原始記錄列表?以下是我的代碼。

import java.util.*; 

class RunnableProcess implements Runnable { 
    private int[] data; 

    public RunnableProcess(int[] data) { 
     this.data = data; 
    } 

    public void run() { 
    try { 

     // sort the records this thread has access to 
     for (int i = 0; i < data.length; i++) { 
     Arrays.sort(data[i]); 
     } 

    } catch(Exception ex) { 
     ex.printStackTrace(); 
    } 
    } 
} 

class BigData { 

    static int[][] data = new int[1000][1000]; 

    public static void main(String [] args) { 


    // Create records 
    for (int i = 0; i < data.length; i++) { 
     for (int j = 0; j < data[0].length; j++) { 
     data[i][j] = new Random().nextInt(999); 
     } 
    } 

    // Call on two threads to sort the data variable 
    // ExecutorService executor = Executors.newFixedThreadPool(2); 


    // Python type of idea: Pass half the records to each thread and start 
    // java doesn't support this so what is the java way of doing this? 

    // Thread thread = new Thread(new RunnableProcess(data[:499])); 
    // thread.start(); 

    // Thread thread = new Thread(new RunnableProcess(data[499:])); 
    // thread.start(); 

    } 
} 

我很樂意提供解決此問題的最佳方法。

+2

查看'ArrayList'和['ArrayList <> #subList()'](https://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#subList(int ,%20int)) – AJNeufeld

+0

你已經忘記了你需要做的第三步 - 合併排序後的結果。看看合併排序算法! –

回答

1

Java不支持以與python相同的方式對本地數組進行分片。我們可以靠近,使用ArrayList

首先,旁邊。您隨機生成數據的效率非常低。您正在爲您生成的每個隨機數字創建一個新的Random數字生成器對象。你只需要一臺發電機,像這樣:

Random rnd = new Random();      // Only created once 
for (int i = 0; i < data.length; i++) { 
    for (int j = 0; j < data[0].length; j++) { 
     data[i][j] = rnd.nextInt(999); 
    } 
} 

一旦你創建的數據,我們可以把這個本地int[][]二維陣列成List的記錄,其中每個記錄是int[] 1D陣列:

List<int[]> records = Arrays.asList(data); 

請注意,這不會複製數組中的值。它創建一個List視圖的數組。存儲在data中的值的任何更改都將反映在records中,反之亦然。

我們這樣做,所以我們可以使用List#subList()方法將列表分成兩個視圖。

List<int[]> first_half = records.subList(0, 500); 
List<int[]> second_half = records.subList(500, 1000); 

再次,這些是視圖,由原始列表支持(由原始數組支持)。通過視圖進行的更改將反映在原始視圖中。

因爲我們現在有存儲,而不是一個陣列中的List,記錄,我們需要更新RunnableProcess使用這種新的格式:

class RunnableProcess implements Runnable { 
    private List<int[]> records; 

    public RunnableProcess(List<int[]> records) { 
     this.records = records; 
    } 

    @Override 
    public void run() { 
     // sort the records this thread has access to 
     for (int[] record : records) { 
      Arrays.sort(record); 
     } 
    } 
} 

現在我們已經將數據劃分爲兩個獨立的組,和可以在每組上操作的RunnableProcess。現在,我們可以開始多線程了。

ExecutorService executor = Executors.newFixedThreadPool(2); 

此執行服務創建兩個線程池,並會一遍又一遍重複使用這些線程提交到這個執行後續任務。正因爲如此,你做不是需要創建並開始自己的線程。執行者會照顧這一點。

executor.submit(new RunnableProcess(first_half)); 
executor.submit(new RunnableProcess(second_half)); 

因爲我們想知道什麼時候這些任務都完成後,我們需要保存Futureexecutor.submit()返回:

Future<?> task1 = executor.submit(new RunnableProcess(first_half)); 
Future<?> task2 = executor.submit(new RunnableProcess(second_half)); 

調用Future#get()等待完成任務,並檢索結果任務。 (注:由於我們的Runnable不返回一個值,該值null將返回。)

task1.get(); // Wait for first task to finish ... 
task2.get(); // ... as well as the second task to finish. 

最後,你需要#shutdown()執行者,或你的程序可能無法正常終止。

executor.shutdown(); 

完整的示例:

List<int[]> records = Arrays.asList(data); 
List<int[]> first_half = records.subList(0, 500); 
List<int[]> second_half = records.subList(500, 1000); 

ExecutorService executor = Executors.newFixedThreadPool(2); 

try { 
    Future<?> task1 = executor.submit(new RunnableProcess(first_half)); 
    Future<?> task2 = executor.submit(new RunnableProcess(second_half)); 

    task1.get(); // Wait for first task to finish ... 
    task2.get(); // ... as well as the second task to finish. 
} catch (InterruptedException | ExecutionException e) { 
    e.printStackTrace(); 
} 

executor.shutdown(); 

我需要擔心的數據是共享資源?

在這種情況下,沒有。您的data是一組數組。每個線程僅引用data數組(作爲List),以獲得對int[]記錄的引用。 data數組本身不被修改;只有記錄是,但每個只由其中一個線程修改。

如何將每個線程的結果返回到原始記錄列表?

由於記錄正在「排序」排序,因此您的data變量已包含您的排序記錄數組。對Future#get()的調用可確保每個Thread已完成其處理,以便可以再次從主線程安全地訪問數據。

相關問題