HashMap缓存中的同步

use*_*887 7 java multithreading synchronization caching double-checked-locking

我有一个人们要求资源的网络应用程序.为了提高效率,使用同步哈希映射缓存此资源.这里的问题是当同时为同一个未缓存的资源发出两个不同的请求时:检索资源的操作会占用大量内存,所以我想避免为同一个资源多次调用它.

有人可以告诉我,以下代码段是否存在任何潜在问题?提前致谢.

private Map<String, Resource> resources = Collections.synchronizedMap(new HashMap<String, Resource>());

public void request(String name) {

  Resource resource = resources.get(name);

  if (resource == null) {
    synchronized(this) {
      if (resources.get(name) == null) {
        resource = veryCostlyOperation(name); // This should only be invoked once per resource...
        resources.put(resource);
      } else {
        resource = resources.get(name);
      }
    }
  }

  ...

}
Run Code Online (Sandbox Code Playgroud)

axt*_*avt 6

一个可能的问题是您通过veryCostlyOperation()synchronized块内执行来创建不必要的争用,因此许多线程无法同时检索其(独立)资源.这可以通过使用Future<Resource>map的值来解决:

Map<String, Future<Resource>> map = new ConcurrentHashMap<String, Future<Resource>>();    
...
Future<Resource> r = map.get(name);
if (r == null) {
    FutureTask task = null;
    synchronized (lock) {
        r = map.get(name);
        if (r == null) {
            task = new FutureTask(new Callable<Resource>() {
                public Resource call() {
                    return veryCostlyOperation(name);
                }
            });
            r = task;
            map.put(name, r);
        }
    }
    if (task != null) task.run(); // Retrieve the resource
}

return r.get(); // Wait while other thread is retrieving the resource if necessary
Run Code Online (Sandbox Code Playgroud)

  • 这个问题是你可以同时在多个资源上调用`veryCostlyOperation`.OP提到他不想两次在相同的资源上调用它,但这可能是曲线拟合评论.如果在您的代码中同时请求12个差异资源,则将同时进行12次`veryCostlyOperation`调用.如果它们确实非常耗费内存,则可能会耗尽内存. (3认同)