Issue
I'm developing an application (Java & JavaFX) that writes/reads data (a file). The problem is I don't want to restrict user to run only one instance (of my app) at a time, as I really can't think of reliable way of doing that so it works on both Windows and Linuxes (e.g. server), heard of sockets and files - both are defective IMO. As user is able to run multiple instances, writing/reading data (from a file) seems really messy, because there's no guarantee that file locking will work reliably on Windows and Linuxes (FileLock documentation - click here).
To sum up: I can't restrict multiple instances of my app, but that leads to problem with writing/reading data (from a file).
Is there anything I missed? Maybe there's some other way to solve my problem I can't think of? How do the "big" popular programs handle that?
Solution
Suggested: Use a socket solution
You could follow the techniques outlined in an answer to:
FAQ
Addressing some additional questions:
heard of sockets and files - both are defective IMO.
You state your opinion that using sockets to set up a single instance application won’t work well enough for you. You are in the best position to decide that.
For some apps which want to achieve a single instance, the socket-based or file-based solution outlined in the answer to the linked question or other comments will work well enough.
"What happens if more than one user try to run the application? Won't they conflict on opening the socket?"
And:
Also, I can't be sure if chosen port (fixed, since all instances should check for one port) is being used by some other applications/processes
You may be able to address some of these concerns by enhancing the socket-based solutions outlined in the linked questions.
Enhanced Socket Solution Outline
If you want, you can write an enhanced algorithm to deal with some of these issues.
When another app instance startup occurs, you try to connect to a current instance on a well-known socket.
Check the response to the connection.
If it doesn’t respond with the correct protocol response (e.g. matching user and app name) then increment the port by 2 and retry.
Test the response again until either:
You get a match for the app/user combo, then send a signal to that app to display itself.
OR
If you get no match, then create a new instance on the tested open port.
I'm not suggesting you do that, just explaining that it is possible.
Alternative: OS native service
There are also other OS-specific mechanisms for handling this such as Windows or Linux services which you can investigate if you want, those approaches are involved and vary by OS, so I won’t discuss them in detail here.
For the OS-specific solutions, you usually would:
- Create a native package for your app (e.g. using
jpackage
) - Install it.
- Have the installer config the app as a service
- e.g. on linux, create an
init.d
script with apid
file configured viachkconfig
.
- e.g. on linux, create an
- The service launches on boot and stops on shutdown.
- The app is then accessed via a tray icon or something similar
- The means of interaction is often OS version specific.
Alternative: Allow multiple app instances but use a single database instance
You may also consider using a database rather than files for data storage, as a database system can help solve many of the concurrent access issues which can arise with file based solutions. Multiple clients can connect to the database, and the database and your app code can handle locks and collisions on the data access to ensure data integrity is contained. Using such a solution, there is no need to enforce that a single application instance is running for a user (at least from a data integrity perspective).
Answered By - jewelsea
Answer Checked By - Timothy Miller (JavaFixing Admin)