2012-01-17 44 views
1

假設我有一個整數List。我必須乘以100。要與for循環做到這一點我想制定類似如下:爲這樣的情況動態生成線程Java

for(Integer i : numbers){ 
    i = i*100; 
} 

但是,假設由於性能原因我想產卵同時每個號碼一個線程在numbers每個線程返回上執行一次乘法結果相同List。做這樣的事情最好的方法是什麼?

我的實際問題並不像乘法int s那樣微不足道,而是循環的每次迭代需要大量時間的任務,所以我想按順序同時完成所有任務減少執行時間。

+3

如果你在多核機器上運行,只會有更好的性能 - 你可以預期只有2-4倍的性能, - 你還需要嗎? – Hurda 2012-01-17 21:44:47

回答

4

如果您可以使用Java 7,則會爲此問題創建Fork/Join框架。如果沒有,則在this link處有一個JSR166(分支/加入提議)源代碼。

本質上,你會爲每個步驟創建一個任務(對於你的情況,對於數組中的每個索引)並將其提交給可以彙集線程的服務(fork部分)。然後,您等待所有內容完成併合並結果(連接部分)。

使用服務而不是啓動自己的線程的原因是,創建線程可能會產生開銷,在某些情況下,您可能想要限制線程數。例如,如果你使用的是四CPU機器,那麼同時運行四個以上的線程就沒有多大意義。

+0

從技術上講,四核上可能會有更多的線程可用,因爲某些CPU每個核心有多個硬件線程(如果這樣的話大多數有2個線程會導致8個線程),但原理很明確。 +1 from我:) – Thomas 2012-01-17 22:10:32

1

產生一個新的線程

每個號碼在號碼

是不是一個好主意。但是,使用大小與核心/ CPU數量匹配的固定線程池可能會稍微提高性能。

0

如果它是節點上唯一的應用程序,您應該確定哪個線程數最快完成作業(max_throughput)。這取決於你使用多少JIT可以優化你的代碼的處理器,所以沒有一般​​的建議,而是測量。

這之後,你可以通過numbers modulo max_throughput

0

分發作業工作線程池看看ThreadPoolExecutor,併爲每個迭代的任務。先決條件是這些任務是獨立的。

線程池的使用允許您在每次迭代中創建一個任務,但只能像線程一樣同時運行多個任務,因爲您希望減少線程數量,例如減少核心數量或硬件數量線程可用。創建大量的線程會產生反效果,因爲它們需要大量的上下文切換,這會損害性能。

0

我假設你是在商品PC上。你最多有N個線程在你的機器上同時執行,其中N是CPU的核心數量,所以最有可能在[1,4]範圍內。加上共享列表上的爭用。

但更重要的是,產生新線程的代價遠大於乘法的成本。人們可以有一個線程池......但在這種特定情況下,甚至不值得談論它。真。

2

如果你的任務是相互獨立的,你可以使用Executors框架。 請注意,如果您創建的線程數量超過您的CPU核心數量,您將獲得更多速度。

樣品:

class WorkInstance { 
    final int argument; 
    final int result; 

    WorkInstance(int argument, int result) { 
     this.argument = argument; 
     this.result = result; 
    } 

    public String toString() { 
     return "WorkInstance{" + 
       "argument=" + argument + 
       ", result=" + result + 
       '}'; 
    } 
} 

public class Main { 

    public static void main(String[] args) throws IOException, ExecutionException, InterruptedException { 
     int numOfCores = 4; 
     final ExecutorService executor = Executors.newFixedThreadPool(numOfCores); 
     List<Integer> toMultiplyBy100 = Arrays.asList(1, 3, 19); 
     List<Future<WorkInstance>> tasks = new ArrayList<Future<WorkInstance>>(toMultiplyBy100.size()); 
     for (final Integer workInstance : toMultiplyBy100) 
      tasks.add(executor.submit(new Callable<WorkInstance>() { 
       public WorkInstance call() throws Exception { 
        return new WorkInstance(workInstance, workInstance * 100); 
       } 
      })); 

     for (Future<WorkInstance> result : tasks) 
      System.out.println("Result: " + result.get()); 

     executor.shutdown(); 
    } 
} 
+0

根據run()中發生了什麼(例如IO等待),您可能會看到擁有比core更多的執行程序線程的好處。從#核心開始,但測試以找出答案。 – 2012-01-17 22:18:39

1

的快速和骯髒的方式來開始是使用一個線程池,如一個由Executors.newCachedThreadPool()返回。然後創建執行Runnablesubmit()的任務到您的線程池。還請閱讀這些Javadocs鏈接的類和接口,以及很多很酷的東西,您可以嘗試。

請參閱Effective Java, 2nd ed中的併發性章節,以便對多線程Java進行很好的介紹。