我正在尝试弄清楚如何编写线程安全,到期条目,缓存。此缓存将用作no-hits
缓存,因此,如果在某些存储中找不到条目,我会将其放在此缓存中,并在接下来的几分钟内避免后续呼叫。
将有多个线程读取和编写此缓存。
我的应用程序中将只有一个threadsafecache实例。
我不确定在包含方法中删除条目是否会出现同步问题。
如何测试此类的线程安全?
善意
public class ThreadSafeCache
{
private final Clock clock = Clock.systemUTC();
private final Duration expiration = Duration.ofMinutes(10);
private final ConcurrentHashMap<CacheKey, CacheValue> internalMap = new ConcurrentHashMap<>();
public boolean contains(String a, String b, byte[] c, String d)
{
CacheKey key = new CacheKey(a, b, c, d);
CacheValue value = internalMap.get(key);
if (value == null || value.isExpired())
{
internalMap.remove(key);
return false;
}
return true;
}
public void put(String a, String b, byte[] c, String d)
{
internalMap.computeIfAbsent(new CacheKey(a, b, c, d), key -> new CacheValue());
}
private class CacheValue
{
private final Instant insertionDate;
private CacheValue()
{
this.insertionDate = clock.instant();
}
boolean isExpired()
{
return Duration.between(insertionDate,
clock.instant()).compareTo(expiration) > 0;
}
}
}
您在相同功能中调用2个地图操作,这意味着有交织的范围(即,在功能中的2个操作之间发生了另一个操作,改变其行为(。为了解决此问题,您可以将地图操作放在synchronized (internalMap) {}
块中。请注意,您必须使用2个离散方法调用中与地图交互的任何方法进行此操作。
从代码风格的角度来看,在contains
方法中修改地图是不好的做法。这将使您的代码降低。另一个人第一次(或几个月后您(来代码可能不记得contains()
实际上修改缓存。contains
意味着它只是检查缓存而不是修改缓存。
我的建议是:
- 如果钥匙已经过期,只需返回false。
- 在
get()
方法中,检查该值是否已过期,如果有的话,请在那里计算一个新的。
您的问题:"我不确定在包含方法中删除条目是否会出现同步问题"。
=>删除操作没有问题,因为您使用同步集合confurrenthashmap,这是最好的选择。
extra:获得同步集合的另一种方法是:collections.synchonize(mycollection(,但是如果我们在多线程envi中使用删除操作(也许是在循环中(,则它会引发modification exception。
。因此,使用同步集合(例如:concurrenthashmap(是建议