【问题标题】:Is it good practice to submit Runnable to a thread pool in a loop?在循环中将 Runnable 提交到线程池是一种好习惯吗?
【发布时间】:2013-11-03 23:52:27
【问题描述】:

我有以下代码 sn-p,我想知道在线程池上运行任务时,在循环中提交 Runnable 的实例是否是一种好习惯。

我需要访问循环外的列表,这是我的推理。这是伪代码,所以我的真实代码使用 ConcurrentHashMap 的,消除了线程问题。如果这是不好的做法,有没有人有更好的建议?我尝试将其拆分为另一个课程,但遇到了我的外部列表问题。

我不知道何时从内存中清除列表,我无法知道线程何时全部完成。

public void startJob() {
    int threads = Runtime.getRuntime().availableProcessors();
    ExecutorService exec = Executors.newFixedThreadPool(threads);

    final List<ImportTask> importTasks = session.createCriteria(ImportTask.class).list();
    final List<Object> objs = new ArrayList<>();

    int count = 0;

    for (ImportTask importTask : importTasks) {
        exec.submit(new Runnable() {
            @Override
            public void run() {
                count++;

                if(objs.contains(importTask) {
                    obj = objs.get(importTask.indexOf(importTask));
                } else {
                    Object obj = new Object();
                    objs.add(obj);
                    session.save(obj);
                }


                if(count % 50 = 1000) {
                    session.flush();
                    session.commit();
                }
            }
        }
    }
}

【问题讨论】:

  • 这个问题似乎是题外话,因为它是关于审查(可能是有效的)代码。请在codereview.stackexchange.com上提问
  • @Bohemian 这个问题完全是主题,我不需要发布我的确切对象。我只是问用可运行对象循环 ExecutorService 是否是一种好习惯。我在我当前的代码中使用这个循环,但担心问题。
  • 如果可能的话,在 run() 方法中编写循环显然会更好。将 ExecutorService 用作 ersatz 'for' 循环肯定不是好习惯。
  • @EJP 这就是我认为我的问题所在,我需要对 importTask 进行多线程处理,这就是将其保留在 exec 服务之外的原因。将它放在 run 方法中不会使我能够对 importtask 进行多线程处理,还有其他建议吗?
  • 这家伙似乎也有类似的问题,stackoverflow.com/questions/12845881/… 我不应该使用 Runnable 吗?我不知道没有它我可以创建新线程。

标签: java multithreading threadpool


【解决方案1】:

Runnable 的实例提交到线程池是实现任务并发执行的一种完全有效的方法。

要知道每个任务何时完成,请保留ExecutionService.submit() 返回的Future 对象列表。

Future<?> future = exec.submit(new Runnable() {
...
futures.add(future);

最后使用阻塞Future.get()得到每个future的结果。

根据另一个答案的建议,您也可以使用ExecutorService.invokeAll()。不同的是,该方法只需要Callable而不是Runnable,必须一次性提交所有任务,并且该方法一直等到最后一个任务终止。

使您的代码更整洁的进一步步骤是使您的任务 (ImportTask)实现Callable 接口(和call 方法)和返回 em> 这是计算。如果您需要将值传递给任务,例如您的objs 列表,您可以通过ImportTask 的构造函数来完成。

【讨论】:

  • 感谢您的回复。与 pasha701 的使用 invokeAll 答案相比,使用 submit 有什么区别?
【解决方案2】:

要知道所有线程何时完成,您可以使用“ExecutorService.invokeAll”而不是“submit”。

【讨论】:

  • invokeAll 和Wlll 的Future 建议有什么区别?
  • 如果你做“Future>future = exec.submit(new Runnable()..”并且下一条语句将“future.get()”,当前线程将等待Runnable结束,只有将运行一个线程。使用“invokeAll”会运行多个线程,并且只有在所有线程结束时当前线程才会继续。
猜你喜欢
  • 1970-01-01
  • 2014-11-05
  • 2019-11-07
  • 2018-11-17
  • 2017-01-14
  • 1970-01-01
  • 1970-01-01
  • 2017-02-21
  • 2022-01-20
相关资源
最近更新 更多