我的要求是这样的:
我编写了一个代码来检查数据库中的数据,如果找不到数据,它会使用第三方rest API来获取数据。执行一些逻辑,最后获得的数据存储在数据库中。
public void exampleMethod(){
MyObject myObj = getObjFromDatabase(); //getting from db
if(myObj==null){ //not found in db
myObj = getObjFromThirdParty(); //consuming rest api
//some logic here in case myobj is not in db....
}else{
//some other logic here in case myobj is in db...
}
saveObjInDatabase(myObj); //saving it in database
}
我需要将它保存在数据库中一次。从第三方API获取响应需要一些时间,并且此方法从多个线程执行 现在,问题是我需要将它保存在数据库中一次,但是在一个线程可以在数据库中保存数据之前,另一个线程从数据库中获取空值,这个逻辑只有在"数据不在db&#34时才会执行;执行并多次保存相同的数据。 (我使用mongoDB来存储数据) 我怎么解决这个问题?谢谢。
答案 0 :(得分:0)
您要问的是缓存。这是一个应该正常工作的例子。如果需要加载对象,它会在getObj
上同步。如果对象是新鲜的,那么getObj
会很快返回并且几乎不会阻塞其他线程,但是如果它需要加载对象,那么其他线程将一直等到对象被加载。
public class Test {
// used when you want to refresh the cached object
private static boolean refreshNext = false;
// a static reference to your object that all threads can use
private static MyObj cachedObj = null;
private static void message(String msg) {
System.out.println(
System.currentTimeMillis() + " : " + Thread.currentThread().getName() + " : " + msg);
}
private static void sleep(long milli) {
try { Thread.sleep(milli); } catch (Exception e) { }
}
// represents the object stored in the db
private static MyObj myObjInDb = null;
private static void saveObjInDb(MyObj obj) {
// TODO do real saving to db and handle errors
message("storing in db...");
myObjInDb = obj;
}
private static MyObj loadObjFromDb() {
// TODO do real loading from db and handle errors
message("getting from db...");
sleep(1000);
return myObjInDb;
}
private static MyObj loadObjFromVendor() {
// TODO do real fetching from vendor and handle errors
message("getting from vendor...");
sleep(2000);
return new MyObj();
}
private static MyObj loadObj() {
message("loading object...");
MyObj obj = loadObjFromDb();
if (obj == null) {
message("db didn't have it.");
obj = loadObjFromVendor();
saveObjInDb(obj);
}
return obj;
}
/** Returns the object, first loading and caching if needed. */
public static synchronized MyObj getObj() {
// only one thread can get the object at a time, in case it needs to be loaded.
if (cachedObj == null || refreshNext) {
// load and cache the object
cachedObj = loadObj();
refreshNext = false;
}
return cachedObj;
}
public static void exampleMethod() {
MyObj obj = getObj();
message(obj.toString());
// ... do stuff with obj
}
private static class MyObj {
public final String data = "I have data!";
@Override public String toString() { return data; }
}
public static void main(String[] args) {
for (int i = 0; i < 20; i++)
new Thread(Test::exampleMethod).start();
}
}