Reputation: 1541
Every time a page is requested on my website, I log some details with a service call like this:
logService.logPageRequest(session, request, contentId);
This service call makes use of a static FileUtils (my own) method to do the actual update on the file.
public static void appendToTextFile(String string, String fileRootDirectory, String subdirectory, String filename, boolean startOnNewLine) throws Exception {
// code irrelevant to the question removed
String filePath=fileDirectory+"/"+filename;
File file=new File(filePath);
if(file.exists()) {
FileWriter out = new FileWriter(filePath, true);
if(startOnNewLine) {
out.write("\r\n");
}
out.write(string);
out.close();
} else {
FileWriter out = new FileWriter(filePath);
out.write(string);
out.close();
}
Every so often (let's say scheduled every 15 minutes), I execute another service which renames this file and starts processing it.
I'd like to understand how I can go about ensuring that both concurrent writes are safe and rename is not executed while a write is in the process. I guess the answer will be some form of synchronization.
Upvotes: 1
Views: 3180
Reputation: 7278
The two services need to share a synchronization object: it can be anything (even new byte[1]
) but it must be the one and same instance, passed into your "services". Whenever there is a critical section, which means part of a code which wants to operate on a shared resource, it needs to be wrapped in
synchronized(theInstanceOfSynchronizationObject) {
// ... your code for critical section
}
The rule of good locking is to know deterministically what are you locking, what is exactly the shared resource. What will kill you (and introduce deadlocks) is random adding of synchronized blocks in hope of "solving". In your particular example, it's most probably the actions on file
: just actions, not the operations on filename strings, neither the instantiation of File
: you can have many File
objects pointing to the same file on disk and it's not a critical operation, as long as it does not touch the disk yet. So i would say
File file=new File(filePath);
synchronized(theInstanceOfSynchronizationObject) {
if(file.exists()) {
} else {
}
}
Similarly, protect the File
actions in your other service. Keep in mind that it's not File
object you are protecting, but the file itself.
Upvotes: 2