我将couchbase初始化代码放在一个静态代码块中:
static {
initCluster();
bucket = initBucket("graph");
metaBucket = initBucket("meta");
BLACKLIST = new SetObservingCache<String>(() -> getBlackList(), BLACKLIST_REFRESH_INTERVAL_SEC * 1000);
}我知道这不是一个很好的实践,但它非常方便,并且达到了它的目的,因为我需要这段代码在多线程环境中运行一次,并阻止其他线程的所有后续调用,直到它完成为止(黑名单已经初始化)。
令我惊讶的是,对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()的调用会阻塞所有其他线程,这些线程试图检查一个条目是否黑名单,直到黑名单被初始化。我不太喜欢这个解决方案,因为它非常冗长且容易出错--人们可能会尝试从黑名单中读取,而不事先调用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;
}发布于 2016-02-07 14:30:45
第一:你在做复核成语。那总是很糟糕。只放置一个if(BLACKLIST==null),它必须在同步的内部。
第二:懒散init很好,但是在静态getInstance()中这样做,并且从不公开黑名单字段。
https://stackoverflow.com/questions/33982030
复制相似问题