java - Grails 中的多线程 - 将域对象传递到每个线程会导致某些字段随机为空

标签 java multithreading grails groovy threadpool

我试图通过引入并行编程来加速 Grails 应用程序中的进程。这个特定的过程需要筛选数千个文档,从中收集必要的数据并将其导出到 Excel 文件。

经过几个小时的尝试追查此过程为何进行得如此缓慢后,我确定该过程必须做大量工作来从每个域对象收集数据的特定部分。 (示例:域对象内部有数据列表,此过程获取这些列表中的每个索引,并将其附加到带逗号的字符串中,以在 Excel 工作表的单元格中创建一个美观的排序列表。还有更多示例但这些应该不重要。)

因此,任何不是简单数据访问的内容(document.id、document.name 等)都会导致此过程花费很长时间。

我的想法是为每个文档使用线程来异步获取所有这些数据,当每个线程完成数据收集后,它可以返回主线程并放入excel表中,现在所有数据访问都非常简单,因为线程已经收集了所有数据。

这似乎有效,但是我在域对象和线程方面遇到了错误。每个线程都会传入其相应的文档域对象,但无论出于何种原因,文档域对象都会随机将其部分数据更改为 null。

例如:在将文档传递到线程之前,域对象的一部分将有一个如下所示的列表:[美国,英格兰,威尔士],随机在任何一点,该列表将如下所示线程:[美国,空,威尔士]。这种情况会在任何随机时间发生在域对象的任何随机部分。

生成线程:

def docThreadPool = Executors.newFixedThreadPool(1)
def docThreadsResults = new Future<Map>[filteredDocs.size()]
filteredDocs.each {
    def final document = it
    def future = docThreadPool.submit(new DocumentExportCallable(document))
    docThreadsResults[docCount] = future
    docCount++
}

从线程中获取数据:

filteredDocs.each {
        def data = docThreadsResults[count].get()

        build excel spreadsheet...
}

DocumentExportCallable 类:

class DocumentExportCallable implements Callable {
    def final document

    DocumentExportCallable(document) {
        this.document = document
    }

    Map call() {
            def data = [:]

            code to get all the data...

            return data
    }
}

编辑: 如下所示,如果我可以向您展示域对象,将会很有用。但是我无法做到这一点。但是,你们向我询问有关域对象的事实让我认为这可能就是问题所在。事实证明,域对象在线程中随机困惑的每个部分都是“映射”内域对象中的一个变量,它使用 SQL 连接来获取这些变量的数据。我刚刚了解到 Grails 中的惰性获取与急切获取。我想知道这是否可能是问题所在......默认情况下它被设置为延迟获取,因此每个线程对数据库的持续访问可能是出现问题的地方。我相信找到一种方法将其更改为急切获取可能会解决问题。

最佳答案

我知道为什么这些空值随机出现。现在一切似乎都正常,我的实现现在的执行速度比以前的实现快得多!

事实证明,即使在获取对象本身之后,当您访问这些字段时,具有 1-m 关系的 Grails 域对象也会进行单独的 sql 调用。这肯定导致这些线程进行非线程安全的 SQL 调用,从而创建了这些随机空值。在这种特定情况下将这些 1-m 属性设置为急切地获取可以解决该问题。

对于稍后阅读的任何人,您都需要阅读有关惰性获取与急切获取的内容,以便更好地理解。

至于代码:

这些是我的域对象中出现问题的 1-m 变量:

static hasMany = [propertyOne : OtherDomainObject, propertyTwo : OtherDomainObject, propertyThree : OtherDomainObject]

我在数据库调用中添加了一个标志,该标志将针对此特定情况启用此代码,因为我不希望始终在整个应用程序中急切地获取这些属性:

if (isEager) {
    fetchMode 'propertyOne', FetchMode.JOIN
    fetchMode 'propertyTwo', FetchMode.JOIN
    fetchMode 'propertyThree', FetchMode.JOIN
    setResultTransformer Criteria.DISTINCT_ROOT_ENTITY
}

我很抱歉,但目前我不记得为什么我必须将“setResultTransformer”放在上面的代码中,但如果没有它就会出现问题。也许稍后有人可以解释这一点,否则我相信谷歌搜索会解释。

关于java - Grails 中的多线程 - 将域对象传递到每个线程会导致某些字段随机为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42701650/

相关文章:

java - 使用 JAXB 和 Stax 对 XML 文档进行验证

java - 我必须跟踪 eclipse 中的执行流程

通过命名管道实现的客户端-服务器多线程程序

grails - Spring Security UI-禁用在RegisterController上发送邮件

java - OS X 系统代理的 JVM 自动设置如何工作?

java - 在java中一行声明多个对象

android - Android 中的动画和多线程

java - 在Java中建立happens-before关系

amazon-web-services - Grails Amazon Web Services插件route53使用Route53时出错Error ChangeResourceRecordSets

web-services - 从命令行调用 REST WS