4

次の形式のスレッドがあります。

  1. 各スレッドの各実行は、クラス内の関数を実行することになっています。その関数は、単独で実行しても完全に安全です。この関数は値、たとえば int を返します。

  2. すべてのスレッドが実行された後、関数値を累積する必要があります。

したがって、(疑似コードで)次のようになります。

  a = 0
  for each i between 1 to N
      spawn a thread independently and call the command v = f(i)
      when thread finishes, do safely: a = a + v
  end

その場合のJavaの使い方がわかりません。

問題はスレッドを作成することではありません。これを使用して実行できることはわかっています

new Thread() { 
   public void run() { 
     ... 
   } 
} 

問題はすべての答えを蓄積することです。

情報をありがとう。

4

2 に答える 2

4

私はおそらく次のようなことをします:

 public class Main {
     int a = 0;
     int[] values;
     int[] results;

     public Main() {
         // Init values array

         results = new int[N];
     }

     public int doStuff() {
         LinkedList<Thread> threads = new LinkedList<Thread>();

         for (final int i : values) {
             Thread t = new Thread() {
                 public void run() {
                     accumulate(foo(i));
                 }
             };

             threads.add(t);
             t.start();
          }

          for (Thread t : threads) {
              try {
                  t.join();
              } catch (InterruptedException e) {
                  // Act accordingly, maybe ignore?
              }
          }

          return a;
     }

     synchronized void accumulate(int v) {
          // Synchronized because a += v is actually
          //    tmp = a + v;
          //    a = tmp;
          // which can cause a race condition AFAIK
          a += v;
     }
 }
于 2012-09-20T22:38:51.830 に答える
3

ExecutorCompletionService、、ExecutorおよびCallable.を使用します。

関数Callableを呼び出すa から始めます。int

public class MyCallable implements Callable<Integer> {
    private final int i;

    public MyCallable(int i) {
        this.i = i;
    }

    public Integer call() {
        return Integer.valueOf(myFunction(i));
    }
}

を作成しますExecutor

private final Executor executor = Executors.newFixedThreadPool(10);

10一度に実行するスレッドの最大数です。

次に、それをラップして、ExecutorCompletionServiceジョブを送信します。

CompletionService<Integer> compService = new ExecutionCompletionService<Integer>(executor);

// Make sure to track the number of jobs you submit
int jobCount;
for (int i = 0; i < n; i++) {
    compService.submit(new MyCallable(i));
    jobCount++;
}

// Get the results
int a = 0;
for (int i = 0; i < jobCount; i++) {
    a += compService.take().get().intValue();
}

ExecutorCompletionService完了したタスクをキューから引き出すことができます。これは、スレッドの結合とは少し異なります。全体的な結果は同じですが、スレッドの完了時に UI を更新する場合、結合を使用してスレッドがどの順序で完了するかわかりません。最後のforループは次のようになります。

for (int i = 0; i < jobCount; i++) {
    a += compService.take().get().intValue();
    updateUi(a);
}

これにより、タスクが完了すると UI が更新されます。スレッドが完了する順序ではなく、結合を呼び出した順序で結果が得られるため、 a を使用してThread.joinも必ずしもこれが行われるわけではありません。

エグゼキューターを使用することで、同時に実行するジョブの数を制限できるため、誤ってシステムをスレッド爆撃しないようにすることもできます。

于 2012-09-20T23:05:35.503 に答える