ConsurrentHashmap删除钥匙



我正在尝试弄清楚如何编写线程安全,到期条目,缓存。此缓存将用作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(是建议

最新更新