-1

使这个自定义 LinkedHashMap 自定义缓存示例线程安全的最佳方法是什么?

 public class Cache extends LinkedHashMap<Object, Object>{
        private static final long serialVersionUID = -4297992703249995219L;
        private final int cacheSize;
        public Cache(int size){
            super(size + 1, .75f, true); 
            this.cacheSize=size;
        }

         protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {
            return size() > cacheSize;
         }
    }


public class Main {
    public static void main(String[] args) {
        Cache cache = new Cache(2);
        cache.put(1, "one");
        cache.put(2, "two");

        for(Entry<Object, Object> entry : cache.entrySet()){
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
    }
}
4

3 回答 3

1

我建议您遵循 SLaks 在评论中的建议并使用ConcurrentHashMap并发库中的一个或其他数据结构,而不是尝试使非并发数据结构线程安全的更困难的任务。

一种解决方案是使用 aConcurrentHashMap和 a ConcurrentLinkedQueue- 每当您将键值对添加到映射时,也将其键添加到队列中,并轮询队列以删除最旧的映射条目。一个潜在的复杂情况是您的线程的交错将导致在将对象添加到队列之前将其添加到映射中 - 我不认为这是一个问题,因为您只需要队列的顺序大致匹配将键值对添加到映射的顺序。

如果您希望能够在它们过期之前从映射中删除键值对,则此解决方案是有问题的,因为您可能需要遍历整个队列以删除已从映射中删除的键。这个问题最简单的解决方案是永远不要从队列中删除键,除非通过轮询它(即,如果你从映射中删除键值对,那么不要从队列中删除键) - 你会有一些队列中的键与映射中的键不对应,但这只是一个问题,因为它会导致队列大于所需的大小 - 映射的正确性不会受到影响。

于 2013-07-19T02:55:42.437 回答
1

我在这里有一个很长很复杂的答案,但后来我意识到这实际上和说的一样:

Map<K,V> myMap = Collections.<K,V>synchronizedMap(new LinkedHashMap<K,V>());

myMap 现在是线程安全的 LinkedHashMap。无需创建新类。

于 2013-07-19T02:58:34.990 回答
1

ConcurrentHashMap 与 HashMap 类非常相似,只是 ConcurrentHashMap 提供内部维护的并发性。这意味着在多线程应用程序中访问 ConcurrentHashMap 时不需要同步块。

//Initialize ConcurrentHashMap instance
ConcurrentHashMap<String, Integer> m = new ConcurrentHashMap<String, Integer>();

//Print all values stored in ConcurrentHashMap instance
for each (Entry<String, Integer> e : m.entrySet())
{
system.out.println(e.getKey()+"="+e.getValue());
}

上面的代码在您的应用程序的多线程环境中是合理有效的。我说“合理有效”的原因是,上面的代码虽然提供了线程安全,但仍然会降低应用程序的性能。并引入了 ConcurrentHashMap 以提高性能,同时确保线程安全。

为了提高它的性能,您可以根据需要调整以下参数:

  • 初始容量
  • 负载因子
  • 并发级别
于 2013-07-19T04:51:43.893 回答