Mik*_*son 5 java synchronization locking double-checked-locking
Checkstyle将此代码报告为"双重检查锁定习语已损坏",但我认为我的代码实际上并未受到双重检查锁定问题的影响.
如果不存在具有该id的行,则该代码应该在数据库中创建一行.它在多线程环境中运行,我想避免主键存在的SQL异常.
伪代码:
private void createRow(int id) {
Row row = dao().fetch(id);
if (row == null) {
synchronized (TestClass.class) {
row = dao().fetch(id);
if (row == null) {
dao().create(id);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我可以同意它看起来像双重检查锁定,但我没有使用静态变量,fetch()和create()中的代码可能太复杂,无法内联并使其无序.
我错了还是格式?:)
我认为在这种情况下,checkstyle是正确的.在您提供的代码中,考虑如果两个线程都row == null
在synchronized块的入口处会发生什么.线程A将进入块,并插入新行.然后在线程A退出块后,线程B将进入块(因为它不知道刚刚发生了什么),并尝试再次插入相同的新行.
我看到你刚刚更改了代码,并在那里添加了一个非常重要的缺失行.在新代码中,您可能能够避免这种情况,因为两个线程不会依赖于对共享(静态)变量的更改.但是你可能会更好地看看你的DBMS是否支持如下的语句INSERT OR UPDATE
.
将此功能委派给DBMS的另一个好理由是,您需要部署多个应用程序服务器.由于synchronized
块不能跨机器工作,因此无论如何都必须在其他情况下执行其他操作.
假设您希望最里面的行读取:
row = dao().create(id);
Run Code Online (Sandbox Code Playgroud)
dao().fetch
假设从 create 方法正确互斥,这不是一个经典的双重检查锁问题。
编辑:(代码已更新)
双重检查锁的经典问题是在初始化发生之前分配一个值,其中两个线程正在访问相同的值。
假设 DAO 已正确同步并且不会返回部分初始化的值,则不会受到双重检查锁习惯用法的缺陷的影响。