问题
Is my below method thread safe? This method is in Singleton class.
private static final Map<String, PreparedStatement> holder = new ConcurrentHashMap<>();
public BoundStatement getStatement(String cql) {
Session session = TestUtils.getInstance().getSession();
PreparedStatement ps = holder.get(cql);
if(ps == null) { // If "ps" is already present in cache, then we don't have to synchronize and make threads wait.
synchronized {
ps = holder.get(cql);
if (ps == null) {
ps = session.prepare(cql);
holder.put(cql, ps);
}
}
}
return ps.bind();
}
I am working with Cassandra and using datastax java driver so I am reusing prepared statements and that's why I am caching it here. Prepared Statement and BoundStatement.
Is there any better way of making my getStatement
method thread safe (if it is thread safe) instead of using synchronized block like that? Any other data structure which might be thread safe for these kind of operations? I am working with Java 7.
回答1:
Since .putIfAbsent is in Java7, you can use 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);
if(ps == null) { // If "ps" is already present in cache, then we don't have to synchronize and make threads wait.
if (holder.putIfAbsent(cql, session.prepare(cql)) != null) {
// Someone else got there before, handle
}
}
return ps.bind();
}
Note that putIfAbsent still uses same synchronization internally.
回答2:
If you're looking to do some form of memoization, then this is the best/easiest you can do in Java 7. Guava has a computing Cache implementation you can use and Java 8 has a computeIfAbsent
method in the Map
interface, but you're obviously out of luck here.
If you can create objects on an empty race, like Alexey's answer suggests, that would be the best solution. If you cannot, your implementation is both thread-safe and reasonable.
It is a form of double-checked locking, however, with this implementation you are ensuring a happens-before ordering by using the put
and get
methods of the CHM.
来源:https://stackoverflow.com/questions/40831817/how-to-make-concurrent-hash-map-thread-safe-with-get-and-put-as-an-atomic-operat