Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 检查数据库中是否存在数据,并使用多个线程插入新数据(如果未找到)?_Java_Multithreading - Fatal编程技术网

Java 检查数据库中是否存在数据,并使用多个线程插入新数据(如果未找到)?

Java 检查数据库中是否存在数据,并使用多个线程插入新数据(如果未找到)?,java,multithreading,Java,Multithreading,我的要求是这样的: 我已经编写了一个代码来检查数据库中的数据,如果找不到数据,它将使用第三方RESTAPI来获取数据。执行一些逻辑,最后将获得的数据存储在数据库中 public void exampleMethod(){ MyObject myObj = getObjFromDatabase(); //getting from db if(myObj==null){ //not found in db my

我的要求是这样的:
我已经编写了一个代码来检查数据库中的数据,如果找不到数据,它将使用第三方RESTAPI来获取数据。执行一些逻辑,最后将获得的数据存储在数据库中

 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获取响应需要一些时间,并且此方法从多个线程执行。
现在的问题是,我需要在数据库中只保存一次,但在一个线程可以在数据库中保存数据之前,另一个线程从数据库中获取null,只有当“数据不在数据库中”时才执行的逻辑会被执行,并多次保存相同的数据。(我正在使用mongoDB存储数据)
我怎样才能解决这个问题?多谢各位

您要问的是缓存。下面是一个应该正常工作的示例。它在
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();
    }
}
公共类测试{
//要刷新缓存对象时使用
private static boolean refreshNext=false;
//所有线程都可以使用的对对象的静态引用
私有静态MyObj cachedObj=null;
专用静态无效消息(字符串消息){
System.out.println(
System.currentTimeMillis()+“:”+线程.currentThread().getName()+“:”+消息);
}
专用静态无效睡眠(长毫秒){
尝试{Thread.sleep(milli);}catch(异常e){}
}
//表示数据库中存储的对象
私有静态MyObj myObjInDb=null;
私有静态void saveObjInDb(MyObj obj){
//TODO真正保存到db并处理错误
消息(“存储在数据库中…”);
myObjInDb=obj;
}
私有静态MyObj loadObjFromDb(){
//TODO从db执行实际加载并处理错误
消息(“从数据库获取…”);
睡眠(1000);
返回myObjInDb;
}
私有静态MyObj loadObjFromVendor(){
//TODO从供应商处进行实际提取并处理错误
消息(“从供应商处获取…”);
睡眠(2000年);
返回新的MyObj();
}
私有静态MyObj loadObj(){
消息(“正在加载对象…”);
MyObj obj=loadObjFromDb();
if(obj==null){
消息(“db没有它。”);
obj=loadObjFromVendor();
saveObjInDb(obj);
}
返回obj;
}
/**返回对象,如果需要,首先加载和缓存*/
公共静态同步MyObj getObj(){
//如果需要加载对象,一次只能有一个线程获取该对象。
if(cachedObj==null | | refreshNext){
//加载并缓存对象
cachedObj=loadObj();
refreshNext=false;
}
返回cachedObj;
}
公共静态void示例方法(){
MyObj obj=getObj();
消息(obj.toString());
//…用obj做事
}
私有静态类MyObj{
public final String data=“我有数据!”;
@重写公共字符串toString(){return data;}
}
公共静态void main(字符串[]args){
对于(int i=0;i<20;i++)
新线程(Test::exampleMethod).start();
}
}

简短的回答是“锁定”。我想说的是,您可能应该在数据库端执行锁定,这样,如果您曾经有多个JVM在同一个数据库上同时运行此代码,那么它就会工作。会是这样吗?如果没有,那么您可以在Java代码中使用锁定。上下文不清楚,但听起来好像多个线程正在创建一个
myObj
,其中每个线程的
myObj
只是同一对象的不同实例。最简单的方法是同步
exampleMethod()
。同步
exampleMethod()
可能是最简单的解决方案,但如果有许多并发读取,则会阻塞很多数据,而无需这样做。只有当另一个线程正在更新该值时,线程才需要停止并等待。