我把我的couchbase初始化代码放在一个静态代码块中:
static {
initCluster();
bucket = initBucket("graph");
metaBucket = initBucket("meta");
BLACKLIST = new SetObservingCache<String>(() -> getBlackList(), BLACKLIST_REFRESH_INTERVAL_SEC * 1000);
}
我知道这不是一个好习惯,但它非常方便并且达到了它的目的,因为我需要这个代码在多线程环境中运行一次并阻止来自其他线程的所有后续调用,直到它#&# 39;完成(黑名单已初始化)。
令我惊讶的是,对getBlacklist()的调用超时并且无法完成。
但是,在2分钟后再次调用它时(ObservingCache
执行的操作),它会在不到一秒的时间内完成。
为了解决这个问题,我重构了我的代码并使黑名单获取变得懒惰:
public boolean isBlacklisted(String key) {
// BLACKLIST variable should NEVER be touched outside of this context.
assureBlacklistIsPopulated();
return BLACKLIST != null ? BLACKLIST.getItems().contains(key) : false;
}
private void assureBlacklistIsPopulated() {
if (!ENABLE_BLACKLIST) {
return;
}
if (BLACKLIST == null) {
synchronized (CouchConnectionManager.class) {
if (BLACKLIST == null) {
BLACKLIST = new SetObservingCache<String>(() -> getBlackList(), BLACKLIST_REFRESH_INTERVAL_SEC * 1000);
}
}
}
}
对isBlacklisted()
的调用会阻止尝试检查条目是否被列入黑名单的所有其他线程,直到黑名单被初始化为止。
我不是这个解决方案的忠实粉丝,因为它非常冗长且容易出错 - 有人可能会先尝试从BLACKLIST读取而不事先调用assureBlacklistIsPopulated()
。
该类中的静态(和非最终)字段如下:
private static CouchbaseCluster cluster;
private static Bucket bucket;
private static Bucket metaBucket;
private static SetObservingCache<String> BLACKLIST;
当它不是静态初始化块的一部分时,我无法弄清楚调用成功的原因。是否存在我不知道的静态初始化块的与性能相关的已知漏洞?
编辑:为每个请求添加了初始化代码
private Bucket initBucket(String bucketName) {
while(true) {
Throwable t = null;
try {
ReportableThread.updateStatus("Initializing bucket " + bucketName);
return cluster.openBucket(bucketName);
} catch(Throwable t1) {
t1.printStackTrace();
t = t1;
}
try {
ReportableThread.updateStatus(String.format("Failed to open bucket: %s reason: %s", bucketName, t));
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void initCluster() {
CouchbaseEnvironment env = DefaultCouchbaseEnvironment
.builder()
.kvTimeout(MINUTE)
.connectTimeout(MINUTE)
.retryStrategy(FailFastRetryStrategy.INSTANCE)
.requestBufferSize(16384 * 2)
.responseBufferSize(16384 * 2)
.build();
while(true) {
ReportableThread.updateStatus("Initializing couchbase cluster");
Throwable t = null;
try {
cluster = CouchbaseCluster.create(env, getServerNodes());
if(cluster != null) {
return;
}
} catch(Throwable t1) {
t1.printStackTrace();
t = t1;
}
try {
ReportableThread.updateStatus(String.format("Failed to create connection to couch %s", t));
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public Set<String> getBlackList() {
ReportableThread.updateStatus("Getting black list");
AbstractDocument<?> abstractDoc = get("blacklist", metaBucket, JsonArrayDocument.class);
JsonArrayDocument doc = null;
if (abstractDoc != null && abstractDoc instanceof JsonArrayDocument) {
doc = (JsonArrayDocument)abstractDoc;
} else {
return new HashSet<String>();
}
ReportableThread.updateStatus(String.format("%s: Got %d items | sorting items", new Date(System.currentTimeMillis()).toString(), doc.content().size()));
HashSet<String> ret = new HashSet<String>();
for (Object string : doc.content()) {
if (string != null) {
ret.add(string.toString());
}
}
return ret;
}
答案 0 :(得分:1)
第二:懒惰初始化很好,但是在静态getInstance()中执行它,并且永远不要公开BLACKLIST字段。