I've got a problem with my program. An external system calls multiple times my program asking to write a line on the same file. The problem is when all the process is done the file has got less lines than I expected. I guess there is a concurrency problem. I've tried to lock the file by RandomAccessFile's Channel but I can't understand if doing so I can avoid completely the problem.
I've tried also to introduce a random Thread.sleep but it's not strong this solution.
Any suggestions? Are there different ways to do what I want?
First what do you expect the resulting file looks like? Questions to ask are:
Are you trying to append data or overwrite data to that file?
If appending, is the file pointer at the correct place when you start writing (check the RandomAccessFile API)?
I doubt there are any issues with threads or concurrency in your case.
I have to append lines. The external system reads a table of elements and sends each row to my program that has to write the file. The first problem is that each call to my program creates a new instance of my program (consuming a lot of memory) and each call has to write the own line appending on the same file. If the external system reads 100 rows, the final file should have got 100 lines. I can't understand how solve this problem.
Sounds dicey. If there are multiple JVM instances running this program at the same time, what would prevent the following scenario?
Process A sets position to end of file, let's say position 1234.
Process B sets position to end of file, again 1234.
Process A writes a record to position 1234. The new end of file is now later, let's say 1345.
Process B writes a record to position 1234, overwriting previous record.
It's one of the standard scenarios for concurrent threads, except since these are different processes, it's even harder to fix. There may be some guarantees somewhere in RandomAccessFile, or maybe FileChannel, that would fix this. But I don't see them, yet. I suspect this sort of thing is what's causing the problem seen by the original poster here. I'm not sure what the best solution is though.
A file channel that is open for writing may be in append mode, for example if it was obtained from a file-output stream that was created by invoking the FileOutputStream(File,boolean) constructor and passing true for the second parameter. In this mode each invocation of a relative write operation first advances the position to the end of the file and then writes the requested data. Whether the advancement of the position and the writing of the data are done in a single atomic operation is system-dependent and therefore unspecified.
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.
Sounds like it should work however for regulating competition between two different JVMs. However I would test this carefully to be sure; I seem to recall that locks on Windows can behave quite differently than locks on Mac. To test, try inserting a nice big Thread.sleep() in between setting the position and writing, and run a couple programs at the same time. That will make it easy for them to collide, if the locks allow them to collide.
Hey! Wanna see my flashlight? It looks like this tiny ad: