I am working with Cassandra and using Datastax Java driver. I am trying to reuse prepared statements by caching it.
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 of datastax java driver.
This getStatement
method will be called by multiple threads so I have to make sure it is thread safe. I am working with Java 7.
What will putIfAbsent
do here if we get two same cql prepared statements? Is my code thread safe and there is no race condition?
Update:-
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();
}
Your code has a race condition which can result in session.prepare(cql)
being called twice (or more) for any cql
parameter. The putIfAbsent
doesn't really offer any advantage over a normal put
in this case.
If you were on Java 8, you could write this efficiently without creating duplicates with
PreparedStatement ps = holder.computeIfAbsent(cql, key -> session.prepare(key));