我有一个下面的Singleton类,在我的getStatement
方法中,我通过检查来填充CHM。
public class CacheHolder {
private static final Map<String, PreparedStatement> holder = new ConcurrentHashMap<>();
private static class Holder {
private static final CacheHolder INSTANCE = new CacheHolder();
}
public static CacheHolder getInstance() {
return Holder.INSTANCE;
}
private CacheHolder() {}
public BoundStatement getStatement(String cql) {
Session session = TestUtils.getInstance().getSession();
PreparedStatement ps = holder.get(cql);
if (ps == null) {
ps = session.prepare(cql);
holder.put(cql, ps);
}
return ps.bind();
}
}
我的getStatement
方法线程是否安全?
答案 0 :(得分:2)
@javaguy提供的答案是正确的,但只是一个小优化,以确保在不需要时为每个线程执行同步块。
public static BoundStatement getStatement(String cql) {
PreparedStatement ps = null;
Session session = null;
try {
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);
}
}
}
} finally {
//release the resources
}
return ps.bind();
}
您也可以使用Guava Cache,或者如果您想要地图Guava MapMaker。
使用番石榴缓存:
LoadingCache<String, PreparedStatement> cache = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build(
new CacheLoader<String, PreparedStatement>() {
public PreparedStatement load(String cql) throws Exception {
return createPreparedStatement(cql);
}
});
使用地图制作工具:
ConcurrentMap<String, PreparedStatement> cache = new MapMaker()
.concurrencyLevel(32)
.weakValues()
.makeComputingMap(
new Function<String, PreparedStatement>() {
public PreparedStatement apply(String cql) {
return createPreparedStatement(cql);
}
});
另外,我建议不要缓存PreparedStatement&#39; ,因为这些资源需要发布 AFAIK。
答案 1 :(得分:1)
请参阅@Bandi Kishore的答案,因为它比下面的答案更有效(对于synchronization
的每次调用,以下答案都需要getStatement()
,可以通过再添加一个{{1}来避免检查)。
我的getStatement方法线程是否安全?
不,它不是线程安全的,在您的null
方法中,您正在进行 getStatement(String cql)
检查竞争条件,这通常被称为双重检查锁定,您可以查看here。即,当线程正在执行null
时,代码中存在竞争条件,您需要holder.get(cql);
该代码的关键部分,如下所示:
synchronize
另外,作为旁注,请确保您正在释放资源。