1

我编写了一项服务,为用户在我的网站上动态上传的图像生成缩略图。这是它的工作方式:

获取缩略图:

  1. 检查之前是否请求过此缩略图
  2. 如果不是,将原始图像调整为请求的大小并将其缓存在硬盘上
  3. 返回缓存在硬盘上的缩略图

上传另一张图片:

  1. 检查这张图片之前是否上传过(例如用户可能正在更新他的头像,旧的可以删除)
  2. 如果是,请删除旧图像的所有缩略图
  3. 保存/覆盖新上传的图像

问题出在第 2 点。当用户请求缩略图时。如果两个用户在完全相同的时间请求相同的缩略图并且之前没有调整大小怎么办?这两个请求都会告诉服务器调整原始图片的大小并将其保存在硬盘上。这两个请求会同时尝试在硬盘上写入同一个文件,从而导致明显的访问问题。

如何避免 Spring MVC 中的这种冲突?所有这些缩略图逻辑都在 Spring 控制器中进行管理,如下所示:

@RequestMapping("/images/{width:\\d{1,10}}x{height:\\d{1,10}}/{subject:.+}.{ext:png|gif|jpg|PNG|GIF|JPG}")
public void thumbnail(HttpServletResponse response,
                   HttpServletRequest request,
                   @PathVariable("width") int width,
                   @PathVariable("height") int height,
                   @PathVariable("subject") String subject,
                   @PathVariable("ext") String ext) throws IOException
{
    // ...
}
4

1 回答 1

1
  • 检查文件是否存在。

  • 如果文件不存在:

    • 创建一个ReentrantLock,并将其存储在一个ConcurrentHashMap中,以文件的路径为key,使用该putIfAbsent()方法。

    • 如果putIfAbsent()返回一个锁,那么在下面使用这个锁。否则,请使用您创建并存储在地图中的锁。

    • 获取 ReentrantLock 上的锁。

    • 获得锁后,检查文件是否存在。如果没有,请创建它。否则,您无需做任何事情,因为之前有一个并发线程创建了它。

    • 释放锁并将其从地图中移除(在 finally 块中)。

  • 读取文件并返回其内容。

于 2012-05-09T10:54:16.093 回答