从Java线程返回值

Lan*_*ali 18 java concurrency multithreading

我有一个类似以下的Java线程:

   public class MyThread extends Thread {
        MyService service;
        String id;
        public MyThread(String id) {
            this.id = node;
        }
        public void run() {
            User user = service.getUser(id)
        }
    }
Run Code Online (Sandbox Code Playgroud)

我有大约300个ID,每隔几秒钟 - 我启动线程来为每个id打个电话.例如.

for(String id: ids) {
    MyThread thread = new MyThread(id);
    thread.start();
}
Run Code Online (Sandbox Code Playgroud)

现在,我想从每个线程收集结果,并对数据库进行批量插入,而不是每2秒进行300次数据库插入.

知道我怎么能做到这一点?

dav*_*veb 35

规范的方法是使用a Callable和a ExecutorService. submita Callable到a ExecutorService返回一个(类型安全)Future,你可以从中get得到结果.

class TaskAsCallable implements Callable<Result> {
    @Override
    public Result call() {
        return a new Result() // this is where the work is done.
    }
}

ExecutorService executor = Executors.newFixedThreadPool(300);
Future<Result> task = executor.submit(new TaskAsCallable());
Result result = task.get(); // this blocks until result is ready
Run Code Online (Sandbox Code Playgroud)

在你的情况,你可能想使用invokeAll它返回ListFutures为你添加任务执行人,或创建一个列表你自己.要收集结果,只需打电话get给每一个.


eri*_*son 19

如果要在执行数据库更新之前收集所有结果,可以使用该invokeAll方法.如果您一次提交一项任务,这就照顾了所需的簿记,如daveb建议的那样.

private static final ExecutorService workers = Executors.newCachedThreadPool();

...

Collection<Callable<User>> tasks = new ArrayList<Callable<User>>();
for (final String id : ids) {
  tasks.add(new Callable<User>()
  {

    public User call()
      throws Exception
    {
      return svc.getUser(id);
    }

  });
}
/* invokeAll blocks until all service requests complete, 
 * or a max of 10 seconds. */
List<Future<User>> results = workers.invokeAll(tasks, 10, TimeUnit.SECONDS);
for (Future<User> f : results) {
  User user = f.get();
  /* Add user to batch update. */
  ...
}
/* Commit batch. */
...
Run Code Online (Sandbox Code Playgroud)