Java 重用ThreadPoolExecutor与创建和处理临时线程?

Java 重用ThreadPoolExecutor与创建和处理临时线程?,java,multithreading,concurrency,threadpoolexecutor,Java,Multithreading,Concurrency,Threadpoolexecutor,我正在构建一个多线程进程,它有两个阶段,每个阶段迭代未知数量的对象(来自缓冲查询结果集或文本文件的数十万个对象)。每个阶段都将启动每个对象的可运行或可调用,但所有可运行/可调用必须在进入下一阶段之前完成 我不想使用闩锁或任何类型的同步器,因为我不想影响吞吐量。我怀疑闩锁的内部结构会使同步计数器的运行速度减慢。我也不想在invokeAll()中使用未来列表,因为我想在遍历可运行文件时立即开始执行它们 然而,为每个阶段创建一个ThreadPoolExecutor,循环并提交所有可运行程序,然后为每个

我正在构建一个多线程进程,它有两个阶段,每个阶段迭代未知数量的对象(来自缓冲查询结果集或文本文件的数十万个对象)。每个阶段都将启动每个对象的可运行或可调用,但所有可运行/可调用必须在进入下一阶段之前完成

我不想使用闩锁或任何类型的同步器,因为我不想影响吞吐量。我怀疑闩锁的内部结构会使同步计数器的运行速度减慢。我也不想在invokeAll()中使用未来列表,因为我想在遍历可运行文件时立即开始执行它们

然而,为每个阶段创建一个ThreadPoolExecutor,循环并提交所有可运行程序,然后为每个阶段关闭它似乎是一个功能解决方案

public void runProcess() {

ResultSet rs = someDbConnection.executeQuery(someSQL);

ExecutorService stage1Executor = Executors.newFixedThreadPool(9);
while (rs.next()) { 
//SUBMIT UNKNOWN # OF RUNNABLES FOR STAGE 1
}
rs.close();
stage1Executor.shutdown(); 

rs = someDbConnection.executeQuery(moreSQL);

ExecutorService stage2Executor = Executors.newFixedThreadPool(9);
while (rs.next()) {  
//SUBMIT UNKNOWN # OF RUNNABLES FOR STAGE 2
}
rs.close();
stage2Executor.shutdown();

}

但是,我知道设置线程、线程池以及任何涉及并发性的操作都需要花费高昂的构建和销毁成本。或者,这没什么大不了的,我只是对性能过于谨慎,因为不管怎样并发都会带来昂贵的开销。有没有更有效的方法?使用某种我不知道的等待完成操作?

如果您破坏线程池并重新初始化一个新的线程池,可能比使用倒计时锁花费更多

此外,调用
stage1Executor.shutdown()
不保证所有当前线程将在新ExecutorService启动和运行之前完成其执行。即使调用
shutdownNow()
也不能保证这一点!(您可能不想调用
shutdownNow()
,因为您希望线程完成执行)

唐纳德·克努斯曾经说过:

过早优化是万恶之源


所以,即使你没有被我说服——最好听他的:)

设置和拆除一些线程池是可以忽略的。在测试中进行循环测试

使用倒计时锁存器是可以的,但这可能只是重复ThreadPoolExecutor在内部所做的工作,并将您的任务与您的执行框架相耦合。我不喜欢这种方法

对于原始代码,ExecutorService有一个
awaitTermination
方法,因此您可以等到工作完成后再进入下一阶段


就我而言,你的伪代码很好。只需将executor.shutdown()替换为
shutdownAndWaitTermination(ExecutorService)
,其来源如下:

因此,如果我使用相同数量的对象(我提前计数)创建201331个可运行项,请使用该数字创建一个Countdownlock,并让每个可运行项递减Countdownlock。。。倒计时锁存器不会因为内部同步而阻塞并发吗?我猜它里面有一个原子整数或其他东西,可能会限制吞吐量。我得到了过早的优化等等,但这个过程目前是单线程的,需要性能优化。@ThomasN。如果您创建的是200K个线程,那么您就做错了:我没有创建200K个线程,我创建的是排队在9个线程上执行的200K个可运行程序。我从并发性研究(Goetz的“实践中的并发性”)中得到的印象是,并发迭代应该这样做。@ThomasN。太好了——这确实是一种方法!让所有人在开始任务2之前完成第一个任务的方法是使用倒计时锁存器(而不是自己尝试实现它)。@Thomas N:我向你保证,不要考虑锁存器中的原子整数,每个线程池执行器实现都至少有一个原子变量,每个任务都要操作一次。如果您真的认为一次原子更新的成本比您的Runnable应该做的要高,那么您的操作碎片化太多了。在不同的并发工具之间切换永远不会解决这样的问题。我可能会采用这种方法,因为我不希望提前知道计数。不过我会付入场费去看你和阿尔法辛。