2011-06-30 37 views
0

我得到了固定數量的線程。我希望每個線程都能一個接一個地運行三個Runnable。下面是一些僞代碼來解釋:Java - 每個線程的多個Runnables

Thread[] threads = new Thread[4]; 

for (int i = 0; i < threads.length; i++) { 
    // Set the first tasks. 
    threads[i] = new Thread(new FirstRunnable()); 
    threads[i].start(); 
} 

for (int i = 0; i < threads.length; i++) 
    threads[i].join(); // wait until the first tasks are done 

for (int i = 0; i < threads.length; i++) { 
    // Set the second task. 
    threads[i].setRunnable(new SecondRunnable()); 
    threads[i].start(); 
} 

for (int i = 0; i < threads.length; i++) 
    threads[i].join(); // wait until the second tasks are done 

... 

使用ThreadPool聽起來方式矯枉過正,特別是因爲我爲首的性能,性能,性能。在Java中實現這個最好的方法是什麼?

+0

這'{0..3} - > 4'螺紋和可運行有 – c00kiemon5ter

+1

[組合兩個Runnable對象]的可能重複(http://stackoverflow.com/questions/4661983/combining-two-runnable -objects) –

+0

@Jon Skeet:在不是所有的FirstRunnable都完成之前,我不想啓動任何'SecondRunnable'。 – ryyst

回答

4

每當您看到new Thread(...).start()時,請使用Executors框架。特別要利用Executors.newFixedThreadPool(...)

+0

爲了完整起見:'執行程序'是一個實用程序類。該框架或者包含捆綁所有用於多線程的高級結構的包是java.util.concurrent包。 – Timmos

1

您可以使用CyclicBarrier和「CombinedRunnable」,如下所示。屏障允許所有線程都等待對方完成,然後再繼續下一個可運行。

CyclicBarrier barrier = new CyclicBarrier(4); 
Runnable r = new CombinedRunnable(barrier, new FirstRunnable(), new SecondRunnable()); 
Thread[] threads = new Thread[4]; 
for (int i = 0; i < threads.length; i++) { 
    threads[i] = new Thread(r); 
    threads[i].start(); 
} 

的CombinedRunnable類:

public class CombinedRunnable implements Runnable{ 

    private final CyclicBarrier barrier; 
    private final Runnable[] runnables; 

    public CombinedRunnable(CyclicBarrier barrier, Runnable... runnables){ 
     this.barrier = barrier; 
     this.runnables = runnables; 
    } 

    /* (non-Javadoc) 
    * @see java.lang.Runnable#run() 
    */ 
    @Override 
    public void run() { 
     for(Runnable r: runnables){ 
      r.run(); 
      try { 
       barrier.await(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } catch (BrokenBarrierException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 
-2

執行人框架是隻爲你。
下面是僞代碼:
1.創建執行服務

Executors type1Runnables = Executors.newFixedThreadPool(4); 
Executors type2Runnables = Executors.newFixedThreadPool(4); 

等。
2.提交任務,它

for(){ 
type1Runnables.submit(new Runnable1()); 
type2Runnables.submit(new Runnable2); 
} 

3.調用執行人

type1Runnables.invokeAll(); 
type2Runnables.invokeAll(); 

爲了使它更通用,你可以編寫自己的executorservicefactory它接受不同的可運行類型。

+0

這段代碼甚至沒有編譯:'Executors'不能被實例化。您的for-loop語法無效。 'ExecutorService.invokeAll(...)'帶參數。這真的是一個非常懶惰和不清楚的答案,所以-1。 – Timmos

1

似乎很適合Executors類中的newFixedThreadPool。

所以,你的代碼看起來是這樣的:

ExecutorService es = Executors.newFixedThreadPool(4); 
List<Future> futures = new ArrayList<Future>(); 
for (int x = 0; x < 4; x ++) { 
    futures.add(es.submit(new FirstRunnable())); 
} 
while (futures.size() > 0) { 
    futures.remove(0).get(); 
} 
for (int x = 0; x < 4; x ++) { 
    futures.add(es.submit(new SecondRunnable())); 
} 

while (futures.size() > 0) { 
    futures.remove(0).get(); 
} 

當然,你也可能很容易地重構上面的代碼刪除代碼重複。

+0

您可以使用CompletionService來避免必須顯式構建和維護期貨列表。 – Adamski

0

實現此目的的一種慣用方法是將ExecutorCompletionService結合使用。這使您可以將許多工作單元映射到固定大小的線程池,並提供了一種優化的阻塞機制,直到所有工作完成。

請注意,您關心如何使用線程池可能會影響效率並不是真正的問題:主要開銷是創建單個線程,無論如何,創建池時額外的對象創建開銷將可以忽略不計。

// Create fixed thread pool and wrap in a CompletionService to allow for easy access to completed tasks. 
// We don't have an explicit result for each Runnable so parameterise the service on Void. 
CompletionService<Void> cs = new ExecutorCompletionService<Void>(Executors.newFixedThreadPool(3)); 

// Create units of work for submission to completion service. 
Runnable[] runnables = ... 

// Submit runnables. Note that we don't care about the result so pass in null. 
for (Runnable r : runnables) { 
    cs.submit(r, null); 
} 

// Take each *completed* result in turn, blocking until a completed result becomes available. 
for (int i=0; i<runnables.length; ++i) { 
    Future<Void> completed = cs.take(); 
} 
相關問題