Java 多线程最佳实践:约束任务newFixedThreadPool
我想在一个包含+-42Mio条记录的数据库上运行很多任务。我希望以5000条记录/次的批量运行此操作(导致850个任务)。 我还想限制java开始为我执行此操作的线程数(16个),我使用当前代码来完成此任务:Java 多线程最佳实践:约束任务newFixedThreadPool,java,multithreading,concurrency,threadpool,Java,Multithreading,Concurrency,Threadpool,我想在一个包含+-42Mio条记录的数据库上运行很多任务。我希望以5000条记录/次的批量运行此操作(导致850个任务)。 我还想限制java开始为我执行此操作的线程数(16个),我使用当前代码来完成此任务: ExecutorService executorService = Executors.newFixedThreadPool(16); for (int j = 1; j < 900 + 1; j++) { int start = (j - 1) * 5000;
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();
}
ExecutorService ExecutorService=Executors.newFixedThreadPool(16);
对于(int j=1;j<900+1;j++){
int start=(j-1)*5000;
int stop=(j)*5000-1;
FetcherRunner runner=新的FetcherRunner(路由、开始、停止);
执行器服务。提交(运行器);
螺纹t=新螺纹(流道);
螺纹列表。添加(t);
t、 start();
}
这是正确的方法吗?特别是在我印象中,java只是启动了所有任务…(
FetcherRunner
实现了runnable
)使用ExecutorService的第一部分看起来不错:
...
FetcherRunner runner = new FetcherRunner(routes, start, stop);
executorService.submit(runner);
有线程的部分不应该在那里,我假设你有它只是为了展示你以前是如何拥有它的
更新:
是的,您不需要在executorService.submit(runner)
之后使用代码,这将产生大量线程。如果您的目标是等待所有提交的任务在循环结束后完成,那么您可以在提交任务时获得对未来
的引用,并等待未来
,如下所示:
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..
}
ExecutorService ExecutorService=Executors.newFixedThreadPool(16);
上市期货=。。;
对于(int j=1;j<900+1;j++){
int start=(j-1)*5000;
int stop=(j)*5000-1;
FetcherRunner runner=新的FetcherRunner(路由、开始、停止);
futures.add(executorService.submit(runner));
}
for(未来:未来){
future.get();//对结果执行一些操作。。
}
这是正确的工作方式吗
第一部分是正确的。但是您不应该创建和启动新的线程对象。提交Runnable时,ExecutorService将其置于队列中,然后在工作线程可用时运行它
。。。。我使用threadlist来检测所有线程何时完成,以便继续处理结果
如果你做了你目前正在做的事情,那么你将运行每个任务两次。更糟糕的是,大量手动创建的线程都将尝试并行运行
确保所有任务都已完成的一个简单方法是调用Executor服务。(如果您不打算再次使用executor服务,则有序关闭executor服务将产生相同的效果。)
另一种方法是为每个
FetcherRunner
的结果创建未来的
,并在提交所有任务后尝试获取结果。这样做的好处是,您可以在生成后续结果之前开始处理早期结果。(但是,如果您不需要…或无法…这样做,使用Futures将无法实现任何目标。)更改代码:
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);
}
ExecutorService ExecutorService=Executors.newFixedThreadPool(16);
对于(int j=1;j<900+1;j++){
int start=(j-1)*5000;
int stop=(j)*5000-1;
FetcherRunner runner=新的FetcherRunner(路由、开始、停止);
执行器服务。提交(运行器);
}
您不需要在调用后提交零件。创建线程的代码将导致创建900个线程!天呐ExecutorService有16个线程池,您可以一次运行16个作业。所有16个线程都忙时提交的任何作业都将排队。从文档中:
创建一个线程池,该线程池重用固定数量的操作线程
分享
无限队列。在任何时候,最多N个线程将是活动的处理任务。
如果在所有线程都处于活动状态时提交其他任务,它们将在
排队等待线程可用。如果任何线程在运行期间由于故障而终止
在关闭前执行,如果需要执行,将替换一个新的
后续任务。池中的线程将一直存在,直到显式关闭
因此,不需要另一个线程。如果您需要在任务完成后得到通知,您可以将其调出。其他选项是缓存从submit返回的所有Future,在每个任务完成后,您可以检查是否所有Future都已完成。在所有的Future都完成之后,您可以分派另一个函数来运行。但它将在ExecutorService中的一个线程上运行。最好的方法是使用countdownlatch,如下所示
ExecutorService executorService = Executors.newFixedThreadPool(16);
CountdownLatch latch = new CountdownLatch(900);
FetcherRunner runner = new FetcherRunner(routes, start, stop, latch);
latch.await();
在FetcherRunner中的finally block下使用latch.countDown()只有当所有任务完成时,才会执行await()
之后的代码。我确实有……但我使用线程列表检测所有线程何时完成,以便继续处理结果。你是在建议我在.submit之后放弃一切吗?+当我在executor上运行900个任务时,如果我将maxThreads限制在10个会有问题吗。@好的,谢谢你的提示,我没有意识到我在复制线程!@比丘、尤在解释发生的事情时最清楚:)