2012-04-04 13 views
2

以下のコードでは、スレッドプール経由で何度も関数を呼び出しています。この機能の中で、FastestMemoryと呼ばれるグローバルアトリビュートを介して、関数の最速実行を追跡します。Executorサービスと非常に高速なJavaコードの終了?

しかし、スレッドプールループの後に値を出力すると、ループ変数ごとにグローバル変数が更新される変数と同じでないように、元の値が与えられます。 FastestMemoryの値が(たとえば)253475に割り当てられていることがわかったときに、2000000000が返されただけです。

1)このコードを再構成して、最も速いものを追跡できるようにする必要がありますか繰り返し?

2)私はこのコードを非常に速く実行できるようですが、4つのXeon x7550で1イタレーション当たり1ミリ秒以下です。これは正常なのですか、どこかでタイミングが間違っていますか? C#は平均で約400ミリ秒かかりますか?

public class PoolDemo { 

    static long FastestMemory = 2000000000; 
    static long SlowestMemory = 0; 
    static long TotalTime; 
    static long[] FileArray; 
    static DataOutputStream outs; 
    static FileOutputStream fout; 


    public static void main(String[] args) throws InterruptedException, FileNotFoundException { 

     int Iterations = Integer.parseInt(args[0]); 
     int ThreadSize = Integer.parseInt(args[1]); 

     FileArray = new long[Iterations]; 
     fout = new FileOutputStream("server_testing.csv"); 

     // fixed pool, unlimited queue 
     ExecutorService service = Executors.newFixedThreadPool(ThreadSize); 
     ThreadPoolExecutor executor = (ThreadPoolExecutor) service; 

     for(int i = 0; i<Iterations; i++) { 
      Task t = new Task(i); 
      executor.execute(t); 
     } 

     executor.shutdown(); 
     service.shutdown(); 

     System.out.println("Fastest: " + FastestMemory); 

     for(int j=0; j<FileArray.length; j++){ 
      new PrintStream(fout).println(FileArray[j] + ","); 
     } 
     } 

    private static class Task implements Runnable { 

     private int ID; 

     static Byte myByte = 0; 

     public Task(int index) { 
      this.ID = index; 
     } 

     @Override 
     public void run() { 
      long Start = System.nanoTime(); 

      int Size1 = 100000; 
      int Size2 = 2 * Size1; 
      int Size3 = Size1; 

      byte[] list1 = new byte[Size1]; 
      byte[] list2 = new byte[Size2]; 
      byte[] list3 = new byte[Size3]; 

      for(int i=0; i<Size1; i++){ 
       list1[i] = myByte; 
      } 

      for (int i = 0; i < Size2; i=i+2) 
      { 
       list2[i] = myByte; 
      } 

      for (int i = 0; i < Size3; i++) 
      { 
       byte temp = list1[i]; 
       byte temp2 = list2[i]; 
       list3[i] = temp; 
       list2[i] = temp; 
       list1[i] = temp2; 
      } 

      long Finish = System.nanoTime(); 
      long Duration = Finish - Start; 
      FileArray[this.ID] = Duration; 
      TotalTime += Duration; 
      System.out.println("Individual Time " + this.ID + " \t: " + (Duration) + " nanoseconds"); 


      if(Duration < FastestMemory){ 
       FastestMemory = Duration; 
      } 
      if (Duration > SlowestMemory) 
      { 
       SlowestMemory = Duration; 
      } 
     } 
     } 
} 

答えて

5

問題は、メインスレッドがエグゼキュータに送信されたタスクが終了するのを待たずに終了していることです。

ExecutorService#shutdownの呼び出し後にExecutorService#awaitTerminationへの呼び出しを追加するだけで実現できます。

もう1つの問題は、static longの値がスレッドの安全性を考慮していないということです。安全なCompare-And-Set操作を取得するには、synchronizeブロックを追加するか、AtomicLongを使用する必要があります。

+0

ありがとうございます!私のタイミングに関する問題はありますか? – mezamorphic

+0

'long '値を変更するために、同期化に関するコメントを追加するように編集しました。同期ブロックは遅くなりますが、AtomicLongは高速ですが使用するのが難しくなります。 –

+0

Upvoted、良いキャッチが、コードに別の問題があります。 –

1

shutdown()は、プールに提出された新しいタスクだけを拒否しますが、すでに送信され実行中のタスクは何もしません。すべてのタスクが完了するまで待機するためには、呼び出す必要があります:

executor.awaitTermination(1, TimeUnit.MINUTES); 
service.awaitTermination(1, TimeUnit.MINUTES); 

はまたFastestMemoryにアクセスし、SlowestMemoryは何とか例えば、同期させる必要があります。

synchronized(PoolDemo.class) { 
    FastestMemory = Math.min(FastestMemory, Duration); 
    SlowestMemory = Math.max(SlowestMemory, Duration); 
} 

ところでJavaのNaming Conventionsに従って:

すべてのインスタンス、クラス、およびクラスの定数は、大文字と小文字が混在しています。小文字の最初の文字はです。

0

最初に、タスクが完了するのを待っていません。 実行者サービスが完了するまで待つ必要があります。

executor.awaitTermination(...); 

また、エグゼキュータとサービスは両方とも同じオブジェクトを参照するため、両方をシャットダウンする必要はありません。実際に私はエグゼクターを雇う理由も見当たりません。呼び出すメソッドはすべてExecutorServiceの一部です。

次に、長い変数の変更はスレッドセーフではありません。比較後に別のスレッドが値を変更するとどうなりますか?長い変数の場合、読み書きはアトミックではありません。これらの変数にはAtomicLongsを使用する必要があります。

AtomicLongから現在の値を取得し、現在の値の実行と比較したいと思うでしょう。新しい値が更新が行われるべきであることを示している場合、compareAndSetを使用して他の誰も値を変更していないことを確認します。他の人が変更した場合は、もう一度チェックを実行してください。

関連する問題