检查数据库中是否存在数据,如果未找到使用多个线程,则插入new?

时间:2018-05-01 12:32:12

标签: java multithreading

我的要求是这样的:
我编写了一个代码来检查数据库中的数据,如果找不到数据,它会使用第三方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来存储数据) 我怎么解决这个问题?谢谢。

1 个答案:

答案 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();
    }
}