我有一个中央数据缓存,它由在 SQL 数据库上运行查询的多个线程进行更新。还有一种机制可以检查数据缓存中最后一个特定项目 (Mydata
) 何时被检索,如果达到某个时间阈值(即,如果数据尚未获取),则关闭相应的线程。在过去 30 分钟内被检索)。该机制的存在是为了尝试减少对数据库的需求并最大限度地减少长时间运行的查询。
还有许多线程从缓存获取数据,因此问题是,即使特定项目 (Mydata
) 不再更新,它也可能被某个线程请求某个点。发生这种情况时,会检查相关线程是否正在运行,如果没有,则会再次启动,如下所示...
private static HashMap<String, MyData> dataMap = new HashMap<>(10);
public static MyData getMyData(String identifier) {
if(!MyThreadManager.getInstance().isRunning(identifier)) {
LOG.info("Thread with identifier={} possibly stopped, restarting.", identifier);
MyThreadManager.getInstance().startThread(identifier);
}
MyData myData= null;
if(dataMap.containsKey(identifier)) {
myData= dataMap.get(identifier);
} else {
LOG.debug("No data found in dataMap for identifier={}, thread possibly terminated. Restarting.", identifier);
}
return myData;
}
...该机制本身工作正常,但我面临这样的风险:当运行 dataMap.get(identifier)
时,它可能仍然只包含 myData 的“过时”版本
(因为重新启动的线程可能仍在处理中)。但是我想保证返回的数据已经更新。为此,我可以在重新启动线程一秒钟后添加一个 sleep 计时器,这应该足以让线程在 dataMap.get(identifier) 之前更新
已运行。dataMap
中的数据
if(!MyThreadManager.getInstance().isRunning(identifier)) {
LOG.info("Thread with identifier={} possibly stopped, restarting.", identifier);
MyThreadManager.getInstance().startThread(identifier);
try {
Thread.sleep(1000L);
} catch (Exception e) {
LOG.error(e.getMessage());
}
}
我在这个实现中遇到的一个大问题是,它可能会对尝试检索信息的任何其他线程产生负面影响。
问题:如何实现线程安全/非锁定方式,以便在线程重新启动时“等待”缓存更新,而不影响使用相同数据缓存的其他线程。
最佳答案
好的,所以进行了一些测试。如果从线程内调用 getMyData 方法...
public class MyRunnable implements Runnable {
private String identifier = "";
public MyRunnable(String identifier) {
this.identifier = identifier;
}
@Override
public void run() {
MyData myData = MyDataManager.getInstance().getMyData(identifier)
System.out.println(String.format("Data retrieved : %s", myData.toString()));
}
}
...然后引入Thread.sleep(1000L);
来重新启动数据收集线程不会对任何其他并发线程产生影响。当然,除非添加 synchronized
方法关键字,这会强制一次一个以避免竞争条件。
由于这些请求的起源最终来自 Servlet 容器处理的 HTTP 请求,因此上面的方法可以正常工作。由于 Servlet 允许 JVM 在单独的 Java 线程中处理每个请求。因此,对 getMyData 方法的每次调用都在其自己的线程上,任何“等待”都会影响其他请求。
关于java - 如何等待数据缓存更新,同时不影响其他缓存调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58724525/