这是双重检查锁定吗?

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()中的代码可能太复杂,无法内联并使其无序.

我错了还是格式?:)

Gre*_*ill 5

我认为在这种情况下,checkstyle是正确的.在您提供的代码中,考虑如果两个线程都row == null在synchronized块的入口处会发生什么.线程A将进入块,并插入新行.然后在线程A退出块后,线程B将进入块(因为它不知道刚刚发生了什么),并尝试再次插入相同的新行.

我看到你刚刚更改了代码,并在那里添加了一个非常重要的缺失行.在代码中,您可能能够避免这种情况,因为两个线程不会依赖于对共享(静态)变量的更改.但是你可能会更好地看看你的DBMS是否支持如下的语句INSERT OR UPDATE.

将此功能委派给DBMS的另一个好理由是,您需要部署多个应用程序服务器.由于synchronized块不能跨机器工作,因此无论如何都必须在其他情况下执行其他操作.


Dus*_*tin 4

假设您希望最里面的行读取:

row = dao().create(id);
Run Code Online (Sandbox Code Playgroud)

dao().fetch假设从 create 方法正确互斥,这不是一个经典的双重检查锁问题。

编辑:(代码已更新)

双重检查锁的经典问题是在初始化发生之前分配一个值,其中两个线程正在访问相同的值。

假设 DAO 已正确同步并且不会返回部分初始化的值,则不会受到双重检查锁习惯用法的缺陷的影响。