How to synchronize file access in a Java servlet?

I created a small Java servlet for a simple purpose: as soon as it is called, it will follow these steps:

  • Read the file foo.json from the local file system
  • Process data from a file and make some changes to it
  • Write the changes to the file

Simplified version of the code:

@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { FileInputStream inputStream = new FileInputStream("foo.json"); String filecontent = IOUtils.toString(inputStream); inputStream.close(); JSONObject json = new JSONObject(filecontent); doSomeChangesTo(json); FileWriter writer = new FileWriter("foo.json"); writer.write(json.toJSONString()); writer.flush(); writer.close(); } 

Now I am faced with a problem that it may happen that a servlet is called almost simultaneously two or more HTTP requests to the servlet. To avoid multiple concurrent access to the record in the same file, I need to somehow synchronize it. From my understanding of the servlet life cycle process, each request spawns a new thread, so using FileLock will probably not affect:

File locks are stored on behalf of the entire Java virtual machine. They are not suitable for controlling access to a file by multiple threads within the same virtual machine.

(From http://docs.oracle.com/javase/7/docs/api/java/nio/channels/FileLock.html )

I assume that using the synchronized(){} keyword will not work either, since I want to synchronize access to the file system and not have access to variables / objects.

So, how do I synchronize access to the file system in my servlet when there are several concurrent requests on this servlet?

+5
source share
3 answers

I assume that using the synchronized(){} keyword will not work either, since I want to synchronize access to the file system, not access to variables / objects.

Using synchronized may work. You are assuming that if you want to control access to an X object from multiple threads, you should use synchronized for this object. You will not do it. You can use synchronized for any object if all calls use the same object.

In fact, it is often better to use a separate private lock object for synchronization, because then it is impossible to lock code outside the class to lock.

So, you might have something like this, with one instance for each shared file:

  public class SharedFile { private final File path; private final Object lock = new Object(); public SharedFile(File path) { this.path = path; } public void process(.....) throws IOException { synchronized(lock) { try(InputStream = new FileInputStream(path)) { .... } } } } 
+6
source

You can use Semaphore as shown below:

 private static Semaphore semaphore = new Semaphore(1); public void doSomeChangesTo(JSONObject json) { try { semaphore.acquire(); // doSomeChangesTo } finally { semaphore.release(); } } 
+3
source

You must use Semaphore to protect access to the resource. (Your file.) See http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html

0
source

Source: https://habr.com/ru/post/1201327/


All Articles