I created a small Java servlet for a simple purpose: Once it is called, it will do the following steps:
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 facing the problem that it could happen that the servlet is called nearly at the same time by two or more http requests to the servlet. To avoid multiple parallel write access on the same file I need to synchronize this somehow. From my understanding of the servlet lifecycle process, each request spawns a new thread, so using FileLock would probably have no affect:
File locks are held 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 guess that using the synchronized(){}
keyword would also not work since I want to synchronize file system access and not access to variables/objects.
So, how can synchronize file system access in my servlet when multiple parallel requests on that servlet happen?
I guess that using the
synchronized(){}
keyword would also not work since I want to synchronize file system access and not access to variables/objects.
Using synchronized
can work. You are assuming that if you want to control access to object X from multiple threads, you must use synchronized
on that object. You don't. You can use synchronized
on any object, provided all the accesses use the same object.
In fact, it is often better to use a separate private
lock object for synchronization, because it is then impossible for code outside the class to synchronize on the 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)) {
....
}
}
}
}
You can use a Semaphore
, as follows:
private static Semaphore semaphore = new Semaphore(1);
public void doSomeChangesTo(JSONObject json) {
try {
semaphore.acquire();
// doSomeChangesTo
} finally {
semaphore.release();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With