Synchronize access to resources in Java (Spring MV

2019-08-14 11:55发布

I coded a service to generate thumbnails for the images dynamically uploaded by users on my website. This is the way it works:

Get thumbnail:

  1. Check whether this thumbnail has been requested before
  2. If not, resize the original image to the requested size and cache it on the hard-drive
  3. Return the thumbnail cached on the hard-drive

Upload another image:

  1. Check whether this image has been uploaded before (e.g. a user may be updating his profile picture, the old one can be deleted)
  2. If yes, delete all the thumbnails of the old image
  3. Save/overwrite the new uploaded image

The problem is on point 2. when a user is requesting a thumbnail. What if two users are requesting the same thumbnail at the exact same time and it has not been resized before? Both the requests will tell the server to resize the original picture and save it on the hard-drive. Both the requests will attempt to write the same file on the hard-drive at the same time, causing obvious access problems.

How can I avoid this conflict in Spring MVC? All this thumbnail logic is managed inside a Spring controller like this:

@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
{
    // ...
}

1条回答
ゆ 、 Hurt°
2楼-- · 2019-08-14 12:25
  • Check for the existence of the file.

  • If the file doesn't exist:

    • create a ReentrantLock, and store it in a ConcurrentHashMap, with the path of the file as the key, using the putIfAbsent() method.

    • If putIfAbsent() returns a lock, then use this lock in the following. Else, use the lock you created and stored in the map.

    • Acquire the lock on the ReentrantLock.

    • Once you have the lock, check if the file exists. If it doesn't, create it. Else, you don't have anything to do because a concurrent thread created it before.

    • Release the lock and remove it from the map (in a finally block).

  • Read the file and return its content.

查看更多
登录 后发表回答