2016-03-17 37 views
1

我正在嘗試總結一個帶有線程的表。我創建一個給定長度的表,然後嘗試創建一個給定名稱的線程總和。與線程表的總和

根據他的indeah,每個線程都佔據了表的一部分。

例如:

表與3個線程12個元素:

0線程取[0,3,6,9]元素

1線程取[1,4,7, 10]元素

2螺紋服用[2,5,8,11]元素

線程被求和該數然後返回結果。之後,我將它們彙總在一起,並獲得結果。

這是我的一個可調用對象實現:

public class TableSumThread implements Callable<Integer> { 

private int indeks; 
private int[] table; 

public TableSumThread(int indeks, int[] table) { 
    this.indeks = indeks; 
    this.table = table; 
} 


@Override 
public Integer call() throws Exception { 
    int iter = indeks; 
    int sum = 0; 
    while(iter < table.length) { 
     sum += table[iter]; 
     iter += indeks; 
    } 
    return sum; 
} 

}

這是我的 「執行人」:

public class TableSumExecutor { 
private int[] table; 
private int executors; 

public Integer execute() { 
    ExecutorService executorService = Executors.newFixedThreadPool(executors); 
    List<Future<Integer>> results = new ArrayList<Future<Integer>>(executors); 

    for (int i = 0; i < executors; i++) { 
     Callable<Integer> task = new TableSumThread(i, table); 
     results.add(executorService.submit(task)); 
    } 
    System.out.println("After creating all threads."); 
    int suma = sum(results); 
    return suma; 
} 

private int sum(List<Future<Integer>> results) { 
    int sum = 0; 
    for (int i = 0; i < results.size(); i++) { 
     try { 
      sum += results.get(i).get(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } catch (ExecutionException e) { 
      e.printStackTrace(); 
     } 
    } 
    return sum; 
} 

主營:

public static void main(String[] args) { 
    Scanner scanner = new Scanner(System.in); 
    System.out.println("Table length: "); 
    int nTable = scanner.nextInt(); 
    System.out.println("Threads number: "); 
    int nThreads = scanner.nextInt(); 

    Random random = new Random(); 
    int[] tablica = new int[nTable]; 
    for (int i = 0 ; i < tablica.length ; i++) 
     tablica[i] = Math.abs(random.nextInt() % 9 + 1); 

    TableSumExecutor tableSumExecutor = new TableSumExecutor(tablica, nThreads); 
    int result = tableSumExecutor.execute(); 

    System.out.println("And the result is: " + result); 
} 

一切都很好,三廣告執行所有任務,但是程序上阻塞:

sum += results.get(i).get(); 

我沒有得到任何異常,它只是堵塞。我也在調試器上檢查它。所有任務都完成了,結果正在等待最後一步。

我可能沒有正確使用Future類型的get()嗎?

編輯。 好的,我解決了一個問題。但是程序畢竟還沒有結束。當我在主executorService.isShutdown()中顯示結果後檢查它是錯誤的。我應該終止所有線程manualy,或者它應該自動終止?

+1

Re,「你可能會發現一些設計錯誤嗎?」比較好的名字,例如:名爲'TableSumThread'的類沒有實現線程。它實現了_task_。任務是代表某件工作需要完成的對象。 _thread_是一個執行代碼的深魔法系統對象,還有一個'ExecutorService'(a.k.a.,_thread pool_)是一個使用一個或多個線程來執行_perform_任務的對象。 –

+1

......而你的'TableSumExecutor'類不是'Executor':這是一個商業邏輯的東西,它使用了一個'ExecutorService'。我會給它一個名稱,說明它的作用(例如,「TableSummer」)。 –

+0

您的程序可能需要更多的時間才能運行,而不是在一個線程中完成所有操作。創建線程需要時間,同步線程需要時間。我不知道在使用多個線程獲得優勢之前數組的大小有多大,但我猜測的是數以萬計的數組元素。 (在實驗中使用你的程序很容易找到答案。) –

回答

1

在這行代碼:

Callable<Integer> task = new TableSumThread(i, table); 

在for循環第一次迭代中, 「i」 你創建indeks TableSumThread對象爲0 = 0。因此,在這個循環:

int iter = indeks; 
int sum = 0; 
while(iter < table.length) { 
    sum += table[iter]; 
    iter += indeks; 
} 

你不增加iter變量,這是無限循環。 這就是爲什麼你的第一個線程永遠不會結束並阻止你的主線程的執行(因爲get()將來的對象阻塞操作)。你可以嘗試傳遞兩個變量 - 開始索引和迭代(在你的情況下 - 常量3)。像新的TableSumThread(我,3,表)。 希望這有助於。

+0

是的,這是一個問題。謝謝。 這是我第一次使用Callable接口的多線程練習。你可能會發現一些設計錯誤,認爲可以以不同的,更好的方式做出來? – nowszy94

+0

您可能會研究一個CompletionService,以避免阻塞Future對象。鏈接在這裏:http://stackoverflow.com/questions/4912228/when-should-i-use-a-completionservice-over-an-executorservice –