"putIfAbsent" 在 CHM 中如何工作?

How does "putIfAbsent" works in CHM?

我正在使用 Cassandra 并使用 Datastax Java 驱动程序。我正在尝试通过缓存来重用准备好的语句。

  private static final ConcurrentHashMap<String, PreparedStatement> holder = new ConcurrentHashMap<>();

  public BoundStatement getStatement(String cql) {
    Session session = TestUtils.getInstance().getSession();
    PreparedStatement ps = holder.get(cql);
    // no statement is cached, create one and cache it now.
    if (ps == null) {
      holder.putIfAbsent(cql, session.prepare(cql));
    }
    return ps.bind();
  }

Prepared Statement and BoundStatement datastax java 驱动程序。

getStatement 方法将由多个线程调用,因此我必须确保它是线程安全的。我正在与 Java 7 合作。

如果我们得到两个相同的 cql 准备语句,putIfAbsent 会在这里做什么?我的代码线程安全并且没有竞争条件吗?

更新:-

  public BoundStatement getStatement(String cql) {
    Session session = TestUtils.getInstance().getSession();
    PreparedStatement ps = holder.get(cql);
    // no statement is cached, create one and cache it now.
    if (ps == null) {
      synchronized (this) {
        ps = holder.get(cql);
        if (ps == null) {
          ps = session.prepare(cql);
          holder.put(cql, ps);
        }
      }
    }
    return ps.bind();
  }

您的代码存在竞争条件,可能会导致 session.prepare(cql) 被任何 cql 参数调用两次(或多次)。 putIfAbsent 在这种情况下并没有真正提供比普通 put 任何优势。

如果您使用的是 Java 8,您可以高效地编写此代码而无需使用

创建重复项
PreparedStatement ps = holder.computeIfAbsent(cql, key -> session.prepare(key));

你确实有竞争条件,但你的 putIfAbsent 可能仍然比纯 put 稍微好一点,因为它保留了旧的声明,所以在实际使用中从来没有两个实例。优势很小,因为它仅在出现竞争条件时才会显现。

它看起来像是 Double-checked locking 的一个版本。如果真的需要,只需在初始化周围放置一个同步块并重新检查。

我对缓存 PreparedStatement 持怀疑态度,因为它是可变的。对于同一个 cql,您可能需要多个实例。这也是可行的,但你需要正确地获取和释放它们。