Java线程队列

时间:2014-08-04 12:31:06

标签: java multithreading threadpool executorservice threadpoolexecutor

我们有一个处理项目的应用程序,在每次迭代时,启动一个线程对另一个数据库进行更新 - 在其他线程上发生的事情并不是非常重要,这是一个非常简单的更新。

我们的初衷是(通过使用一个线程)确保通过初始化与另一个数据库的连接并运行更新来阻止主处理。

昨天,我们遇到了一个问题:(原因尚不明确)数据库速度减慢,并行线程数量下降到天空,导致此数据库中有1000多个连接。所以我们意识到我们需要更多地控制线程。

我需要一个用于我们软件的库或工具,可以:

1)把线程/作业/任务(任何东西 - 我们可以在需要的时候重写代码,我们有一些文件中的Thread对象)放入类似系统的队列中 2)我们可以定义最多同时运行多少个线程 3)线程完成后,线程将从队列中删除,因此GC可以删除所有涉及的实体。

我正在做一些阅读,我找到了ExecutorService(Executors.newFixedThreadPool(5);)但可能会出现问题,因为它失败了3)因为根据javadocs:

  

池中的线程将一直存在,直到明确关闭为止。

我认为,这意味着如果应用程序不断添加线程,则线程将一直存在,直到应用程序重新启动(或者如果我关闭并重新实例化ExecutorService,但这对我来说似乎是个黑客攻击)。

我认为Executors.newFixedThreadPool(5)在我的3)要求失败了吗? 我真的从好的方面得到了问题吗?我需要线程或其他不同的东西吗?

5 个答案:

答案 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 );
    }
}

如果上次更新成功而没有异常,上面的示例将启动对数据库的更新。这样,您可以控制尝试连接的线程数,并捕获导致更新失败的任何错误。