假设我们的应用程序中有一个CountryList对象,该对象应返回国家/地区列表。国家/地区的加载是一项繁重的操作,因此应将列表缓存。
其他要求:
我想出了以下解决方案:
public class CountryList {
private static final Object ONE = new Integer(1);
// MapMaker is from Google Collections Library
private Map<Object, List<String>> cache = new MapMaker()
.initialCapacity(1)
.makeComputingMap(
new Function<Object, List<String>>() {
@Override
public List<String> apply(Object from) {
return loadCountryList();
}
});
private List<String> loadCountryList() {
// HEAVY OPERATION TO LOAD DATA
}
public List<String> list() {
return cache.get(ONE);
}
public void invalidateCache() {
cache.remove(ONE);
}
}
你怎么看待这件事?你看到不好的东西吗?还有其他方法吗?我怎样才能使它更好?在这种情况下,我是否应该寻找另一种解决方案?
谢谢。
谢谢大家 ,尤其是对提出这个想法的用户“ gid ”。
我的目标是考虑到invalidate()操作将被称为非常罕见,从而优化get()操作的性能。
我编写了一个测试类,该类启动了16个线程,每个线程调用get()-Operation一百万次。在本课程中,我介绍了我的2核机器的一些实现。
测试结果
Implementation Time
no synchronisation 0,6 sec
normal synchronisation 7,5 sec
with MapMaker 26,3 sec
with Suppliers.memoize 8,2 sec
with optimized memoize 1,5 sec
1)“不同步”不是线程安全的,但它为我们提供了可以与之相比的最佳性能。
@Override
public List<String> list() {
if (cache == null) {
cache = loadCountryList();
}
return cache;
}
@Override
public void invalidateCache() {
cache = null;
}
2)“正常同步”-相当不错的性能,标准的轻松实现
@Override
public synchronized List<String> list() {
if (cache == null) {
cache = loadCountryList();
}
return cache;
}
@Override
public synchronized void invalidateCache() {
cache = null;
}
3)“使用MapMaker”-性能非常差。
有关代码,请参见顶部的问题。
4)“与Suppliers.memoize”-良好的表现。但是,对于性能相同的“常规同步”,我们需要对其进行优化,或者仅使用“常规同步”。
有关代码,请参见用户“ gid”的答案。
5) “具有优化 的备忘 ” -与“不同步”实现相当的性能,但具有线程安全性。这是我们需要的。
缓存类本身:(此处使用的Supplier接口来自Google Collections
Library,它只有一种get()方法。请参见http://google-
collections.googlecode.com/svn/trunk/javadoc/com/google/ common / base /
Supplier.html
)
public class LazyCache<T> implements Supplier<T> {
private final Supplier<T> supplier;
private volatile Supplier<T> cache;
public LazyCache(Supplier<T> supplier) {
this.supplier = supplier;
reset();
}
private void reset() {
cache = new MemoizingSupplier<T>(supplier);
}
@Override
public T get() {
return cache.get();
}
public void invalidate() {
reset();
}
private static class MemoizingSupplier<T> implements Supplier<T> {
final Supplier<T> delegate;
volatile T value;
MemoizingSupplier(Supplier<T> delegate) {
this.delegate = delegate;
}
@Override
public T get() {
if (value == null) {
synchronized (this) {
if (value == null) {
value = delegate.get();
}
}
}
return value;
}
}
}
使用示例:
public class BetterMemoizeCountryList implements ICountryList {
LazyCache<List<String>> cache = new LazyCache<List<String>>(new Supplier<List<String>>(){
@Override
public List<String> get() {
return loadCountryList();
}
});
@Override
public List<String> list(){
return cache.get();
}
@Override
public void invalidateCache(){
cache.invalidate();
}
private List<String> loadCountryList() {
// this should normally load a full list from the database,
// but just for this instance we mock it with:
return Arrays.asList("Germany", "Russia", "China");
}
}
我正在用本机线程(pthreads)编写一个C应用程序,我需要调用一些Java方法等。我不确定哪些JNI对象可以安全地缓存在我的C对象中,以便以后使用,可能/可能由另一个线程使用。我确实知道,如果我的类的方法可以被不同的线程调用,我不能缓存JNIEnv,而是缓存JavaVM并通过附加当前线程获得JNIEnv。但这是否也意味着我无法缓存从JNIEnv获得的任何内容?我需要使用通过以下JNIEnv方法
问题内容: 考虑几个并行运行的Web服务器实例。每个服务器都有对单个共享“状态保持器”的引用,该角色的作用是保留来自所有服务器的最新请求。 例如(): 在任何时间点,都可以从监视应用程序中调用“状态保持器”,该应用程序读取了最近的SLA报告请求。 在Java中实现这种生产者-消费者方案的最佳方法是什么,使Web服务器具有比SLA报告更高的优先级? CircularFifoBuffer似乎是容纳请求
问题内容: Spring对象是线程安全的吗?如果没有,如何使它们线程安全? 问题答案: 这是两个不相关的问题: spring线程安全吗? 没有。 Spring具有不同的bean 作用域(例如Prototype,Singleton等),但是所有这些作用域都是在创建bean 时强制执行的。例如,每次“注入”一个“原型”范围的bean都会被创建,而一个“单个”范围的bean将被创建一次并在应用程序上下文
我找到了关于线程安全的代码,但它没有来自给出示例的人的任何解释。我想知道为什么如果我不在“count”之前设置“synchronized”变量,那么count值将是非原子的(总是=200是期望的结果)。谢谢
问题内容: 阅读“实践中的Java并发性”,第3.5节包含以下内容: 除了创建两个的明显的线程安全隐患外,该书还声称可能会发生发布问题。 此外,对于诸如 一个可以扔! 这怎么可能?我能想到的唯一允许这种荒谬行为的方法是,如果构造函数不被阻塞,那么当构造函数代码仍在另一个线程中运行时,将创建对实例的引用。 这可能吗? 问题答案: 之所以可行,是因为Java的内存模型较弱。它不保证读写顺序。 可以通过