多线程最佳实践:制约任务的newFixedThreadPool(Multithreading bes

2019-06-26 08:47发布

我要推出很多任务要的+ -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

Answer 1:

使用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..
}


Answer 2:

这是工作的正确方法是什么?

第一部分是正确的。 但你不应该创建并启动新的Thread对象。 当您提交了Runnable的ExecutorService的把它放在它的队列,然后运行它,当一个工作线程变为可用。

....我用的对答时完成我所有的线程,所以我可以继续处理结果来检测。

那么,如果你这样做,你现在在做什么,你在两次运行的每个任务。 更糟糕的是,手动创建的线程群都将尝试以并行方式运行。

一个简单的方法,以确保所有的任务都已完成,是调用awaitTermination(...)的ExecutorService的。 (执行者服务的一个有序的关闭将有同样的效果......如果你不打算再次使用。)

另一种方法是创建一个Future每个FetcherRunner的结果,并试图get所有的任务已经提交后的结果。 这已被生产后来者之前,你可以开始处理结果早的优势。 (不过,如果你不需要......或者不能......做到这一点,利用期货起不到任何东西。)



Answer 3:

你并不需要的部分,来电后提交。 你的代码创建一个线程会导致创建900个线程! Yowza。 该ExecutorService中有16个线程的线程池,你可以同时运行16个作业。 当所有16个线程都在忙着将排队提交的任何作业。 从文档:

创建一个可重用不受限制的队列操作螺纹固定数量的线程池。 在任何时候,顶多来确定nthreads线程将被激活的处理任务。 如果当所有线程是活动的其他任务提交,他们将在队列中等待,直到一个线程可用。 如果任何线程关闭前的执行过程中,由于终止与失败,如果需要执行后续任务的新一个将取而代之。 在池中的线​​程将一直存在,直到它明确地关闭。

因此,有没有需要另一个线程。 如果你需要一个任务完成后得到通知,你可以把它召唤出来。 其他选项是缓存所有的未来的从提交返回,并且一旦完成每一项任务,你可以检查,看看是否所有的Future的完成。 毕竟未来的完成,你可以派遣其他功能来运行。 但它会运行在ExecutorService的一个线程。



Answer 4:

从您的代码更改:

    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);

    }


Answer 5:

最好的办法是使用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()将当所有任务都完成只执行。



文章来源: Multithreading best practices : constraining tasks newFixedThreadPool