[英]Jira: Thread-safe Gadget Data?
我有一些数据(两个HashSet和一个Instantstamp时间戳),我希望将所有对JIRA(OpenSocial?)小工具/插件的请求共享-因为生成时间很长(几分钟),并且共享将有助于提高请求的执行效率。
偶尔(很少),请求可能包含一个参数,该参数指示应刷新此共享数据。 当然,第一次需要它时,它就会被填充。 数据代表过时的答案是可以的-它基于缓慢变化的事物并用于可视化趋势,因此可以容忍一次错误。
我想象当JIRA启动(或上传我的附加组件的新版本)并且在前几分钟出现多个请求时,我需要以线程安全的方式处理这些昂贵的共享数据。 目前,结果看起来不错,但据我了解,这只是偶然的缘故。
只有一个线程需要完成填充工作。 在启动时,其他线程当然必须等待,因为它们不能空手而退。 (如果所有线程都执行昂贵的初始化,则服务器上的不必要的负载很多)
但是在初始成本之后,如果有多个并发请求进入,并且其中一个请求包含“ refresh”参数,则只有一个线程需要为此付出代价-我同意其他线程使用昂贵数据的旧副本的情况从而保持性能,并在响应中包括“是的, 有人正在刷新数据,但这是使用旧副本的结果”。
有关数据的更多信息:两个HashSet和时间戳旨在表示时间上一致的快照。 HashSet的内容仅取决于数据库中的值,并且时间戳只是最近刷新的时间。 这些数据都不依赖于任何较早的快照。 而且它们都不依赖于程序状态。 时间戳仅用于粗略地回答“此数据的年龄”问题。 每次刷新数据时,我都希望时间戳记是较新的,但是如果错误的话,一切都不会中断。 它仅用于调试和透明。 由于快照不依赖于较早的快照或程序状态,因此可以将其包装并标记为易失性。
是否有最佳方法的明显选择? 替代方案的利弊?
您将需要使用Locks来同步对代码部分的访问,而您只需要一次执行一个线程即可。 SO和Oracle Java文档中有大量资源可以更详细地显示如何使用锁,但是类似的方法应该可以解决问题。
这个想法是,您想维护最近生成的一组结果的副本,并且始终返回该副本,直到拥有一组新的可用数据为止。
import java.util.concurrent.locks.ReentrantLock;
public class MyClass
{
private volatile MyObject completedResults;
private final ReentrantLock resultsLock;
private final ReentrantLock refreshLock;
public MyClass()
{
// This must be a singleton class (such as a servlet) for this to work, since every
// thread needs to be accessing the same lock.
resultsLock = new ReentrantLock();
refreshLock = new ReentrantLock();
}
public MyObject myMethodToRequestResults(boolean refresh)
{
MyObject resultsToReturn;
// Serialize access to get the most-recently completed set of results; if none exists,
// we need to generate it and all requesting threads need to wait.
resultsLock.lock();
try
{
if (completedResults == null)
{
completedResults = generateResults();
refresh = false; // we just generated it, so no point in redoing it below
}
resultsToReturn = completedResults;
}
finally
{
resultsLock.unlock();
}
if (refresh)
{
// If someone else is regenerating, we just return the old data and tell the caller that.
if (!refreshLock.tryLock())
{
// create a copy of the results to return, since we're about to modify it on the next line
// and we don't want to change the (shared) original!
resultsToReturn = new MyObject(resultsToReturn);
resultsToReturn.setSomeoneElseIsRegeneratingTheStuffRightNow(true);
}
else
{
try
{
completedResults = generateResults();
resultsToReturn = completedResults;
}
finally
{
refreshLock.unlock();
}
}
}
return resultsToReturn;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.