我在 GAE 中使用 JSR 107 JCache 临时存储从 Web 捕获的数据,并以一定的时间间隔(10 分钟)将其写入数据存储区。我的应用程序只使用一个缓存。大多数时候它运作良好。偶尔(每天 4,000 次中有 5-6 次)缓存中的一个条目由于未知原因而丢失。我对 JCache 不是很熟悉,但我以某种方式理解我的应用程序可能在不同的 JVM 实例上运行,并且我的应用程序可能使用不同的 JCache 实例。
问题可以在下面的日志中找到:
2013-12-31 09:58:14.229 /cron/<myservlet>?code=11 200 ........... app_engine_release=1.8.8 instance=00c61b117c1599a88baa456ae838cbfa9b0f28
2013-12-31 09:58:14.011 <myapp>.RealCache validate: realCache 29829270 retrieved
2013-12-31 09:58:14.117 <myapp>.RealCache validate: Cache contains 0, 1, 2, 3, 4, 5, 6, 8, 11, 12, 13,
2013-12-31 09:58:14.121 <myapp>.RealCache get: Cache 11 has ...... <expected result>......
2013-12-31 09:58:14.121 cron.<myservlet> doGet: Appended with <mydata> for 11
2013-12-31 09:58:14.121 <myapp>.RealCache validate: realCache 29829270 retrieved
2013-12-31 09:58:14.224 <myapp>.RealCache validate: Cache contains 0, 1, 2, 3, 4, 5, 6, 8, 11, 12, 13,
2013-12-31 09:58:14.443 /cron/<myservlet>?code=6 200 ............ app_engine_release=1.8.8 instance=00c61b117c1599a88baa456ae838cbfa9b0f28
2013-12-31 09:58:14.227 <myapp>.RealCache validate: realCache 29829270 retrieved
2013-12-31 09:58:14.326 <myapp>.RealCache validate: Cache contains 0, 1, 2, 3, 4, 5, 6, 8, 11, 12, 13,
2013-12-31 09:58:14.329 <myapp>.RealCache get: Cache 6 has ..... <expected result>......
2013-12-31 09:58:14.329 cron.<myservlet> doGet: Appended with <mydata> for 6
2013-12-31 09:58:14.329 <myapp>.RealCache validate: realCache 29829270 retrieved
2013-12-31 09:58:14.437 <myapp>.RealCache validate: Cache contains 0, 2, 3, 4, 5, 6, 8, 11, 12, 13,
这是我的 servlet 的 2 次执行。如您所见,它们仅在同一 GAE 实例上运行 0.2 秒。“Cache contains 0-13”是realCache中Map的key。“realCache 29829270 retrieved”是我使用的缓存的哈希码。其中有两个,一个在我 get() 缓存时记录,另一个在我 put() 时记录。可以看到,在第二次执行中,get() 和 put() 中的“Cache contains ...”不同,缺少键“1”。这两个执行运行正常,因为不涉及缺少的键“1”。但是,当“code=1”之前为“1”累积的数据丢失时,问题出现在以后的执行中。您可以在下面的编码中看到我想要做什么和我的问题。
这是我的编码(为简单起见跳过了记录代码):
public class RealCache {
private static Cache realCache;
public static synchronized void validate() {
realCache = CacheManager.getInstance().getCache(Constants.Whale);
if (realCache == null) { //for first time of the day
CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
Map<String, Integer> props = new HashMap<>();
props.put(GCacheFactory.EXPIRATION_DELTA, 28800); //8 hrs is enough
realCache = cacheFactory.createCache(Collections.emptyMap());
CacheManager.getInstance().registerCache(Constants.Whale, realCache);
}
}//end validate
public static synchronized MyObj get(int code) {
validate();
MyObj myObj = (MyObj) realCache.get(code);
return myObj;
}//end get
public static synchronized void put(int code, MyObj myObj) {
validate();
realCache.put(code, myObj);
}//end put
}//end RealCache
这是我使用 RealCache 时的代码:
synchronized ("RealCache") {
MyObj myObj = RealCache.get(code);
if (myObj != null) {
myObj.setData(myObj.getData() + newData);
log.info("Appended with "+ newData+ " for "+ code);
} else {
myObj = new MyObj();
myObj.setData(newData);
log.warning("Created with "+ newData+ " for "+ code);
}
RealCache.put(code, myObj);
}//end sync
请告知我的编码有什么问题。