我们有一个处理项目的应用程序,在每次迭代时,启动一个线程对另一个数据库进行更新 - 在其他线程上发生的事情并不是非常重要,这是一个非常简单的更新。
我们的初衷是(通过使用一个线程)确保通过初始化与另一个数据库的连接并运行更新来阻止主处理。
昨天,我们遇到了一个问题:(原因尚不明确)数据库速度减慢,并行线程数量下降到天空,导致此数据库中有1000多个连接。所以我们意识到我们需要更多地控制线程。
我需要一个用于我们软件的库或工具,可以:
1)把线程/作业/任务(任何东西 - 我们可以在需要的时候重写代码,我们有一些文件中的Thread对象)放入类似系统的队列中 2)我们可以定义最多同时运行多少个线程 3)线程完成后,线程将从队列中删除,因此GC可以删除所有涉及的实体。
我正在做一些阅读,我找到了ExecutorService(Executors.newFixedThreadPool(5);)但可能会出现问题,因为它失败了3)因为根据javadocs:
池中的线程将一直存在,直到明确关闭为止。
我认为,这意味着如果应用程序不断添加线程,则线程将一直存在,直到应用程序重新启动(或者如果我关闭并重新实例化ExecutorService,但这对我来说似乎是个黑客攻击)。
我认为Executors.newFixedThreadPool(5)在我的3)要求失败了吗? 我真的从好的方面得到了问题吗?我需要线程或其他不同的东西吗?
答案 0 :(得分:2)
你害怕的句子:
The threads in the pool will exist until it is explicitly shutdown
仅描述对Executors.newFixedThreadPool()的调用。要更好地控制线程池行为,请使用ThreadPoolExecutor constructor expicitly,例如
new ThreadPoolExecutor(1, //minimal Pool Size,
10, // maximal Pool Size,
30, TimeUnit.SECONDS // idle thread dies in 30 seconds
new ArrayBlockingQueue<Runnable>())
答案 1 :(得分:1)
线程将保留在那里(等待其他任务运行),但它不会保留你放在那里的所有数据。当线程池中的线程执行了该任务时,它将执行下一个任务,并且不再引用现有任务。
所以你的恐惧毫无根据,除非你明确地保留对任务的引用。
答案 2 :(得分:1)
将ScheduledExecutorService
与固定的线程池一起使用,无论您需要多少连接。
将BlockingQueue
放入请求中,工作线程在队列中等待,并在出现请求时处理这些请求。
答案 3 :(得分:1)
您需要了解Thread
与Runnable / Callable Task
之间的区别。所以The threads in the pool will exist until it is explicitly shutdown.
的含义是,如果你使用Executors.newFixedThreadPool(5);
,在任何时候线程池中都会有5个线程。您希望这些线程执行的工作将作为Tasks(Runnable / Callable)提交。所以基本上在最大的任何时间点都会有5个线程通过这个线程池执行,在你的情况下将是5个连接。
答案 4 :(得分:0)
ExecutorService是要走的路。它为您提供了底层线程状态的接口(Future),能够检测异常并从已完成的线程返回值。
以下是如何使用ExecutorSerivce和Future接口的简单示例。
public class Updater implements Future< boolean > {
public Updater() { }
public boolean call() throws Exception {
System.out.println( "Hello, World!" );
return true;
}
}
public class Main {
public Main() { }
public static void main( String[] args ) {
ExecutorService pool = Executors.newFixedThreadPool( 1 );
boolean again = true;
do {
if ( again ) {
Future< ? > update = pool.submit( new Updater() );
}
/* Do other work while waiting for update to finish */
if( update.isDone() ) { //may be because of completion or an exception
try {
again = update.get(); // This would block if the Updater was still running
} catch( ExecutionException ee ) { // This is thrown by get() if an exception occurred in Updater.call()
again = false;
ee.printStackTrace();
}
}
} while ( true );
}
}
如果上次更新成功而没有异常,上面的示例将启动对数据库的更新。这样,您可以控制尝试连接的线程数,并捕获导致更新失败的任何错误。