1

在 AJAX 中,假设我异步提交请求。当 reposne 返回时,它会执行一个回调函数。

在 java 多线程环境中实现相同功能的最佳方法是什么?即主线程创建一个子线程并提交一个任务,然后子线程返回一个回调函数,需要由主线程执行。

这可能吗?在主线程中我可以执行 wait() 并且在子线程中我可以执行 notify() 但在这种情况下,主线程将等待子线程完成。但在 AJAX 中,主线程继续其操作......这就是我想要的

4

1 回答 1

3

您可以使用 anExecutorService在后台执行任务,然后使用Future返回的方法等待结果。例如:

class Main {
  private static final ExecutorService es = Executors.newCachedThreadPool();

  public static void main(final String... args) throws Throwable {
    List<Future<Integer>> results = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
      results.add(asyncSum(i, i*i));
    }
    // here, in the main thread, you can do whatever you want
    // while the calculations are performed in background threads
    // ...

    // after the main thread finishes what it was doing, it
    // can process the futures
    for (final Future<Integer> result : results) {
      System.out.println(result.get());
    }
  }

  // this method launches a calculation on a worker thread and immediately
  // returns a Future, which is a reference to the result of the calculation
  // once it is completed
  private static Future<Integer> asyncSum(final int a, final int b) {
    return es.submit(new Callable<Integer>() {
      @Override public Integer call() throws Exception {
        return a + b;
      }
    });
  }
}

在上面的示例中,主线程将阻塞直到第一次计算完成,然后打印它。然后阻塞直到第二次计算完成,然后打印它,等等。

如果您希望在结果可用时打印结果(以未指定的顺序),那么您可以使用 a CompletionService,而不是拥有一个结果列表并对其进行迭代,您可以通过 CompletionService 本身的.take()方法获取您的期货, 阻塞直到计算完成,或者.poll(), 如果有完成的计算返回 Future ,或者 null 如果没有计算完成 - 这样你的主线程将永远不会阻塞。

以下示例使用CompletionService. 它显示了一个永不阻塞的主线程,使用后台线程进行计算并在结果可用时对其进行处理:

class Main {
  public static void main(String[] args) throws Throwable {
    final ExecutorService es = Executors.newCachedThreadPool();
    final CompletionService<Integer> cs = new ExecutorCompletionService<>(es);

    submitSomeCalculations(cs);

    while (true) {
      doMainThreadWork();
      processFinishedCalculations(cs);
    }
  }

  private static void submitSomeCalculations(final CompletionService<Integer> cs) {
    for (int i = 0; i < 10; i++) {
      submitAsyncSum(cs, i, i * i);
    }
  }

  private static void submitAsyncSum(final CompletionService<Integer> cs, final int a, final int b) {
    cs.submit(new Callable<Integer>() {
      @Override public Integer call() throws Exception {
        Thread.sleep(100 + (long) (Math.random() * 900));
        return a + b;
      }
    });
  }

  private static void processFinishedCalculations(final CompletionService<Integer> cs) throws ExecutionException, InterruptedException {
    while (true) {
      final Future<Integer> result = cs.poll();
      if (result == null) {
        System.out.println("> no finished results...");
        break;
      } else {
        System.out.println("> result available: " + result.get());
      }
    }
  }

  static void doMainThreadWork() {
    System.out.println("work from main thread...");
  }
}
于 2013-07-05T19:51:10.697 回答