将Runnable提交到循环中的线程池是一种好习惯吗?

时间:2013-11-03 23:52:28

标签: java multithreading threadpool

我有以下代码片段,我想知道在线程池上运行任务时,在循环中提交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();
                }
            }
        }
    }
}

2 个答案:

答案 0 :(得分:3)

Runnable的实例提交给线程池是实现任务并发执行的完美有效方式。

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

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

最后使用阻止Future.get()获取每个未来的结果。

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

让您的代码更整洁的另一个步骤是让您的任务(ImportTask实现 Callable接口(以及call方法)和返回它的计算。如果您需要将值传递给任务,例如objs列表,则可以通过ImportTask的构造函数执行此操作。

答案 1 :(得分:1)

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