我有一个任务,其中用户使用来自第三方的XML。XML提要每天只更新一次。XML存储在数据库中,并在请求时返回给用户。如果XML不在数据库中,则从第三方检索它,存储在数据库中,然后返回给用户。所有后续请求都将简单地从数据库中读取XML。
现在我的问题是。假设对第三方的请求需要10秒才能返回。在此期间,有多个服务器调用相同的数据。我不希望每一个都向第三方发出请求,也不希望用户什么都没有收到或收到错误。它们可能应该等待第一个请求完成,此时XML将可用。这是一个相对简单的问题,但我想知道解决它的最佳方法是什么。我只是使用一个简单的标志来控制请求或可能像一个信号量?是否有更好的解决方案基于我打算使用的堆栈,即Play框架和cassandra后端。我能用回调或触发器做点什么吗?
顺便说一下,我需要在第一个请求进来时延迟加载数据。因此,在此任务中,不能在单独的进程中或在应用程序启动时获取数据…谢谢
您所需要做的就是创建一个单独的组件,负责从第三方获取XML
并将其保存到数据库。
在你的代码中,不同的线程试图从这个组件中"获取"XML
。
该组件返回数据库中存在的XML
。如果不存在,则使用ReentrantLock进行同步。
因此,执行trylock时,只有一个线程成功。其余的将被封锁。当锁被释放时,其他线程被解除阻塞,但是XML
已经被第一个设法获得锁的线程从第三方获取并存储到数据库中。所以其他线程只是从DB返回XML
。
示例代码(这只是一个"伪代码",让您开始。你应该处理异常等,但可以使用主框架。不要在finally
中忘记unlock
,这样你的代码就不会无限期地阻塞):
public String getXML() {
String xml = getXMLFromDatabase();
if(xml == null) {
if(glocalLock.tryLock()) {
try{
xml = getXMLFromThirdParty();
storeXMLToDatabase(xml);
}
finally {
globalLock.unlock(); //ok! got XML and stored in DB. Wake-up others!
}
}
else {
try{ //Another thread got the lock and will do the query. Just wait on lock!
globalLock.lock();
}
finally {
//woken up but the xml is already fetched
xml = getXMLFromDatabase();
globalLock.unlock();
}
}
return xml;
}