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,ExecutorCallable.:

Callable从调用您的int函数的 a 开始:

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。使用 aThread.join不一定会这样做,因为您将按照调用连接的顺序而不是线程完成的顺序获得结果。

通过使用执行器,这也将允许您限制在给定时间同时运行的作业数量,这样您就不会意外地对系统进行线程轰炸。

于 2012-09-20T23:05:35.503 回答