我正在缓存准备好的语句,以便在使用DataStaxJava驱动程序(cassandra)时不必再次准备它。。下面是我的代码,它可以工作:
private static final ConcurrentHashMap<String, PreparedStatement> cache = new ConcurrentHashMap<>();
public ResultSetFuture send(final String cql, final Object... values) {
return executeWithSession(new SessionCallable<ResultSetFuture>() {
@Override
public ResultSetFuture executeWithSession(Session session) {
BoundStatement bs = getStatement(cql, values);
bs.setConsistencyLevel(consistencyLevel);
return session.executeAsync(bs);
}
});
}
private BoundStatement getStatement(final String cql, final Object... values) {
Session session = getSession();
PreparedStatement ps = cache.get(cql);
// no statement cached, create one and cache it now.
// below line is causing thread safety issue..
if (ps == null) {
ps = session.prepare(cql);
PreparedStatement old = cache.putIfAbsent(cql, ps);
if (old != null)
ps = old;
}
return ps.bind(values);
}
但问题是 send
方法将由多个线程调用,因此我怀疑 getStatement
方法不是线程安全的,因为 if (ps == null)
检查。。我怎样才能保证线程安全?
我想避免使用 synchronize
所以我想看看有没有更好的办法。我现在正在使用Java7。
1条答案
按热度按时间33qvvth11#
你可以用
computeIfAbsent
相反。根据文件:如果指定的键尚未与值关联,则尝试使用给定的Map函数计算其值,并将其输入此Map,除非为null。整个方法调用是以原子方式执行的,因此每个键最多应用一次函数。在计算过程中,其他线程在此Map上尝试的某些更新操作可能会被阻止,因此计算应该简短,并且不能尝试更新此Map的任何其他Map。
代码如下所示:
虽然,因为准备可能需要更长的时间,不建议。。。我会使用显式锁。。。
p、 请注意,java驱动程序4.x有内置的缓存,所以可以多次准备相同的语句。