用于并行处理的Java Executor服务

时间:2018-03-09 19:51:07

标签: java concurrency

在系统上工作以并行支持多个数据库查询。考虑到要从每个数据中查询的数据很多,要求是将每个数据库查询与其他数据库查询分开。意思是,一个数据库/表上的加载不应该对其他表查询产生影响。我使用ExecutorService在Java中开发了一个解决方案。每个数据库使用一个ExecutorService(固定大小,1个线程)。我维护一个DB名称TO ExecutorService的映射,并在接收查询请求时将调用指向相应的执行程序服务。考虑到可以并行查询一百个数据库,不确定ExecutorService是否是正确的选择......!我做了一些评估,初步结果看起来还不错。我对这个解决方案的一个挑战是,当我动态创建ExecutorServices时,我很难在应用程序停止时优雅地关闭它们。

解决此问题的其他方法是维护全局(意味着跨所有数据库)查询工作线程池,并随机重用它们以用于传入请求。但是,这并不能保证所有数据库查询都具有相同的优先级。

DatasetFactory.java

public class DataSetExecutorFactory {

        private static Map<String, DataSetExecutor> executorMap = Collections.synchronizedMap(new HashMap<String, DataSetExecutor>());
    public static DataSetExecutor getDataSetExecutor(String dbName){
            DataSetExecutor executor = null;

            executor = executorMap.get(dbName);
            if(executor == null){
                executor = new DataSetExecutor(dbName);
                executorMap.put(dbName, executor);
            }
            return executor;
        }
    }
}

DataSetExecutor.java

public class DataSetExecutor {

    private ExecutorService executor = Executors.newFixedThreadPool(1);
    public List<Map<String, Object>> execQuery(String collecName, Map<String, Object> queryParams){
        //Construct Query job. 
        //QueryWorker extends 'Callable' and does the actual query to DB
        QueryWorker queryWorker = new QueryWorker(Map queryParams);

        Future<QueryResult> result = null;
        try{
            result = executor.submit(queryWorker);
        }catch (Exception e){
            //Catch Exception here
            e.printStackTrace();
        }
    }

1 个答案:

答案 0 :(得分:0)

我认为你误解了ExecutorService的工作原理。您应该将单个ExecutorService设置为大小为n的FixedThreadPool(n =数据库数量或最大并行查询数量),而不是为每个数据库创建ExecutorService。线程池将为您执行并行处理工作。您只需跟踪数据库名称作为QueryWorker的一部分,该名称将提交给ExecutorService。

这也使得关闭变得容易,因为ThreadPool会自动清理未使用的线程,你只需要在应用程序关闭时关闭它。

尽管如此,由于所有这些并行处理都发生在同一个JVM和同一台机器上,因此您可能会遇到内存或CPU限制,具体取决于查询的强度。