我想在+ -42Mio记录的数据库上运行许多任务。我想分批运行5000个记录/次(结果850个任务)。 我也想限制线程数(到16)java开始为我做这个,我正在使用当前代码来完成这个任务:
ExecutorService executorService = Executors.newFixedThreadPool(16);
for (int j = 1; j < 900 + 1; j++) {
int start = (j - 1) * 5000;
int stop = (j) * 5000- 1;
FetcherRunner runner = new FetcherRunner(routes, start, stop);
executorService.submit(runner);
Thread t = new Thread(runner);
threadsList.add(t);
t.start();
}
这是正确的方法吗?特别是因为我的印象是java只会触发所有任务...(FetcherRunner
实现runnable
)
答案 0 :(得分:4)
使用ExecutorService的第一部分看起来不错:
...
FetcherRunner runner = new FetcherRunner(routes, start, stop);
executorService.submit(runner);
有线程的部分不应该在那里,我假设你在那里只是为了展示你以前如何拥有它?
<强>更新强>
是的,您不需要executorService.submit(runner)
之后的代码,这将最终产生大量的线程。如果您的目标是在循环后等待所有提交的任务完成,那么您在提交任务时可以获得对Future
的引用并等待Future
,如下所示:
ExecutorService executorService = Executors.newFixedThreadPool(16);
List<Future<Result>> futures = ..;
for (int j = 1; j < 900+ 1; j++) {
int start = (j - 1) * 5000;
int stop = (j) * 5000- 1;
FetcherRunner runner = new FetcherRunner(routes, start, stop);
futures.add(executorService.submit(runner));
}
for (Future<Result> future:futures){
future.get(); //Do something with the results..
}
答案 1 :(得分:4)
这是正确的工作方式吗?
第一部分是正确的。但是你不应该创建和启动新的Thread对象。提交Runnable时,ExecutorService会将其放在队列中,然后在工作线程可用时运行它。
....我使用threadlist检测我的所有线程何时完成,以便我可以继续处理结果。
如果您正在执行当前正在执行的操作,那么您将运行两次任务。更糟糕的是,手动创建的线程群将全部尝试并行运行。
确保所有任务都已完成的一种简单方法是在ExecutorService上调用awaitTermination(...)
。 (有序关闭执行程序服务将产生相同的效果......如果您不打算再次使用它。)
另一种方法是为每个Future
的结果创建FetcherRunner
,并在提交完所有任务后尝试get
结果。这样做的好处是,您可以在生成后期结果之前开始处理早期结果。 (但是,如果你不需要......或者不能......这样做,使用Futures将无法实现任何目标。)
答案 2 :(得分:3)
在电话提交后,您不需要该部分。您创建线程的代码将导致创建900个线程! Yowza。 ExecutorService有一个包含16个线程的池,您可以一次运行16个作业。当所有16个线程都忙时提交的任何作业都将排队。来自文档:
创建一个重用固定数量的线程的线程池 共享 无界队列。在任何时候,最多nThreads线程将是活动的处理任务。 如果在所有线程都处于活动状态时提交了其他任务,则它们将等待 队列直到线程可用。如果任何线程由于故障期间终止而终止 在关机之前执行,如果需要执行,新的将取代它 后续任务。池中的线程将一直存在,直到明确关闭为止。
所以不需要另一个线程。如果您需要在任务完成后收到通知,可以让它呼出。其他选项是缓存从提交返回的所有Future,并且在完成每个任务后,您可以检查是否所有Future已完成。完成所有未来之后,您可以发送另一个功能来运行。但它将在ExecutorService中的一个线程上运行。
答案 3 :(得分:0)
从您的代码更改:
ExecutorService executorService = Executors.newFixedThreadPool(16);
for (int j = 1; j < 900 + 1; j++) {
int start = (j - 1) * 5000;
int stop = (j) * 5000 - 1;
FetcherRunner runner = new FetcherRunner(routes, start, stop);
executorService.submit(runner);
}
答案 4 :(得分:0)
最好的方法是使用countdownlatch如下
ExecutorService executorService = Executors.newFixedThreadPool(16);
CountdownLatch latch = new CountdownLatch(900);
FetcherRunner runner = new FetcherRunner(routes, start, stop, latch);
latch.await();
在最终块下的FetcherRunner中,只有在完成所有任务后才会执行latch.countDown();
之后的await()
代码。