Grails 上的同步块适用于 Windows,但不适用于 linux

Posted

技术标签:

【中文标题】Grails 上的同步块适用于 Windows,但不适用于 linux【英文标题】:synchronized block on grails works on windows but no in linux 【发布时间】:2015-10-28 09:31:12 【问题描述】:

我有一个 grails 应用程序,它依赖于服务中的同步块。当我在 Windows 上运行它时,同步按预期工作,但是当我在 ams linux 上运行时,得到一个 StaleObjectStateException。

这个问题在下面的例子中重现。

class TestService 

private final Object $lock = new Object[0];

TesteSync incrementa() 

    synchronized ($lock) 
        TesteSync t = TesteSync.findById(1)
        t.contador++
        t.save(flush: true)

        Thread.sleep(10000)

        return t
    

据我了解,发生此异常是因为多个线程试图保存同一个对象。这就是我使用同步块的原因。

Linux java:

java版本“1.7.0_85” OpenJDK 运行时环境 (amzn-2.6.1.3.61.amzn1-x86_64 u85-b01) OpenJDK 64 位服务器 VM(内部版本 24.85-b03,混合模式)

Windows java:

java版本“1.7.0_79” Java(TM) SE 运行时环境(内部版本 1.7.0_79-b15) Java HotSpot(TM) 64 位服务器 VM(内部版本 24.79-b02,混合模式)

有什么线索吗?

谢谢

【问题讨论】:

只是猜测,也许什么都不会改变:你也可以试试installing the Oracle JDK on linux 吗? 您错过了 InterruptedException 的 try catch 或 throws 你确定你只有一个TestService的实例吗? @RealSkeptic Spring 应该确保服务是 grails 架构下的单例。但无论如何我都会验证 @BackSlash 我也试试 Oracle JDK 【参考方案1】:

你是对的,为什么你会得到 StaleObjectStateException

如果您正在寻找的是悲观锁定(在任何给定时间只允许一个事务访问数据),那么您可以使用域类 lock() 方法:

class TestService 
    static transactional = true

    TesteSync incrementa() 
        TesteSync t = TesteSync.lock(1)
        t.contador++
        return t.save()
    

您可以了解有关 Grails 悲观锁定here 的更多信息。

PS:Grails 服务默认是事务性的。但在我的示例中,我明确地将服务设置为事务性以引起您的注意:Grails 自动释放锁when the transaction commits。我还删除了刷新,因为在事务提交时数据会被刷新。如果您是从未明确设置为 @Transactional 的控制器方法执行此操作,那么您将需要刷新。

提示:当您通过 ID 查询时,您可以这样做...

SomeDomainClass.get(1)

...而不是这个...

SomeDomainClass.findById(1)

【讨论】:

感谢@Emmanuel Rosa,悲观主义锁定方法奏效了!奥布里加多

以上是关于Grails 上的同步块适用于 Windows,但不适用于 linux的主要内容,如果未能解决你的问题,请参考以下文章

QWebEngineView 适用于 Windows,但 Pyside2 中的 OSX 上的灰色空白页面

Stan 代码适用于 Windows 但不适用于 Linux

Ubuntu 上的 X11 转发错误,尽管它适用于 Windows

无法在 Windows 上的适用于 Android 的 Appium 1.4.13.1 上运行任何测试

Windows 上的 git bash shell“您编辑的块不适用”

适用于不同环境的 Grails DB-Migration