2016-05-08 10 views
0

私はいくつかのスレッドを開始するための簡単なプログラムを書いています。スレッドは整数配列から整数nを選択し、それを使用してnを待ち、tの時間を返して、スレッドが結果の配列に戻ってくるのを待ちます。スレッドについて学ぶ

1つのスレッドが終了した場合、次のスレッドを選択する必要があります。まだ別のスレッドに割り当てられていません。
もちろん:整数と結果が一致するように、配列内の順序を維持する必要があります。

私のコードは、わかるようにスムーズに動作します。 私は特に満足のいかないで見つけるとあまり変更することなく、これを解決するための良い方法があると期待したコードブロックの1行を使用しかし:

while(Thread.activeCount() != 1); // first evil line 

を私はちょっと私のすべてのスレッドがすべての取得が完了を確認するために、このラインを乱用私の配列に結果でアクセスする前に、タスクが完了しました。 0.0、Null Pointer Exception ...などの病気の値を防ぐためにこれを行いたいと考えています(実際に使用するクラッシュでアプリケーションを作成する短いものすべて) 建設的な助けがあれば歓迎されます。スレッドのタスクの配列が非常に長くても、コードがスムーズに実行されていれば、結果が整数の順序に一致しなくなってしまうなど、わかりません。

建設的な助けに感謝します。

ファーストクラス:

public class ThreadArrayWriterTest { 

    int[] repitions; 
    int len = 0; 
    double[] timeConsumed; 

    public boolean finished() { 
     synchronized (repitions) { 
      return len <= 0; 
     } 
    } 

    public ThreadArrayWriterTest(int[] repitions) { 
     this.repitions = repitions; 
     this.len = repitions.length; 
     timeConsumed = new double[this.len]; 
    } 

    public double[] returnTimes(int[] repititions, int numOfThreads, TimeConsumer timeConsumer) { 

     for (int i = 0; i < numOfThreads; i++) { 
      new Thread() { 
       public void run() { 
        while (!finished()) { 
         len--; 
         timeConsumed[len] = timeConsumer.returnTimeConsumed(repititions[len]); 
        } 
       } 

      }.start(); 
     } 
     while (Thread.activeCount() != 1) // first evil line 
      ; 
     return timeConsumed; 
    } 

    public static void main(String[] args) { 
     long begin = System.currentTimeMillis(); 
     int[] repitions = { 3, 1, 3, 1, 2, 1, 3, 3, 3 }; 
     int numberOfThreads = 10; 

     ThreadArrayWriterTest t = new ThreadArrayWriterTest(repitions); 
     double[] times = t.returnTimes(repitions, numberOfThreads, new TimeConsumer()); 
     for (double d : times) { 
      System.out.println(d); 
     } 
     long end = System.currentTimeMillis(); 
     System.out.println("Total time of execution: " + (end - begin)); 
    } 
} 

セカンドクラス:

public class TimeConsumer { 

    double returnTimeConsumed(int repitions) { 
     long before = System.currentTimeMillis(); 
     for (int i = 0; i < repitions; i++) { 
      try { 
       Thread.sleep(1000); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
     long after = System.currentTimeMillis(); 
     double ret = after - before; 
     System.out.println("It takes: " + ret + "ms" + " for " + repitions + " runs through the for-loop"); 
     return ret; 
    } 
} 

答えて

1

完了するために、すべてのスレッドを待つための最も簡単な方法は、それらのコレクションを維持し、その後、順番に各1にThread.join()を呼び出すことです。

1

.join()に加えて、あなたがスレッドのプールを管理するためにExecutorServiceを使用することができ、

一つ以上の 非同期タスクの進行状況を追跡するFutureを生成することができ、終了とメソッド を管理するためのメソッドを提供しキュータ。

ExecutorServiceをシャットダウンすると、新しい タスクが拒否されます。 ExecutorServiceをシャットダウンするための2つの異なるメソッドが用意されています。 shutdownNow()メソッド は、待機中のタスクの開始を防ぎ、現在は タスクの実行を停止しようとしていますが、シャットダウン()メソッドは以前にサブミットされた タスクを実行する前に実行できます。終了時には、エグゼキュータには実行中のタスクがありません 実行待ちのタスクはありません。新しいタスクは実行できません 未使用のExecutorServiceをシャットダウンし、 のリソースの再利用を許可する必要があります。

メソッド実行 をキャンセルし、および/または完了を待つために使用することができる未来を作成して戻す によって基本メソッドてexecutor.execute(Runnableを)を拡張提出します。メソッドinvokeAnyとinvokeAllは、 タスクのコレクションを実行し、少なくとも1つまたはすべてを完了してから が完了するまで、最も一般的に便利な一括実行形式 を実行します。

ExecutorService executorService = Executors.newFixedThreadPool(maximumNumberOfThreads); 
CompletionService completionService = new ExecutorCompletionService(executorService); 
for (int i = 0; i < numberOfTasks; ++i) { 
    completionService.take(); 
} 
executorService.shutdown(); 

プラスThreadPoolExecutor

0

を見てみましょうJavaはconcurrentパッケージで、より高度なスレッド化APIを提供するので、あなたは、スレッド管理機構が簡素化され、ExecutorServiceを調べる必要があります。

問題を簡単に解決できます。

  1. 使用エグゼキューAPI

    static ExecutorService newFixedThreadPool(int nThreads) 
    

    スレッドプールを作成し共有アンバウンド形式のキューなしで動作するスレッドの固定数を再利用するスレッドプールを作成します。

  2. すべてのタスクが完了するまで待機するには、invokeAllを使用します。

    サンプルコード:

    ExecutorService service = Executors.newFixedThreadPool(10); 
    
    List<MyCallable> futureList = new ArrayList<MyCallable>(); 
    for (int i=0; i<12; i++){ 
        MyCallable myCallable = new MyCallable((long)i); 
        futureList.add(myCallable); 
    } 
    System.out.println("Start"); 
    try{ 
        List<Future<Long>> futures = service.invokeAll(futureList); 
        for(Future<Long> future : futures){ 
         try{ 
          System.out.println("future.isDone = " + future.isDone()); 
          System.out.println("future: call ="+future.get()); 
         } 
         catch(Exception err1){ 
          err1.printStackTrace(); 
         } 
        } 
    }catch(Exception err){ 
        err.printStackTrace(); 
    } 
    service.shutdown(); 
    

は、同じことを達成するために詳細については、この関連のSEの質問を参照してください。

wait until all threads finish their work in java

関連する問題