I think if you ask people's opinion about singleton most of them will answer that there is nothing wrong with it, but your first choice should go to a non-singleton design. So in this case I can only say, figure out why exactly you want it to be singleton, and then try to find out if there are no other ways to accomplish the same result without singleton. If you cannot find a decent way, or they all interfere with some other design issue, then singleton is probably the way to go.
I did also use singleton, I will explain my situation and the logic which I used to validate the idea of implementing it as singleton. Maybe this will help you to find out if you need it or not.
Based upon your post I think that you nearly have the same design as I do. You have some kind of adapter for which you created a remote interface. The adapter has at most one instance to the Data class. So there will be multiple adapter instances when multiple clients are connected, but they will all share the same Data instance. My design (not all of it, just a snapshot) :
Note: The DatabaseAdapter instances are spawned by the RMI server when a new client connects. At least, this is what I think...
This design offers 2 layers of indepence.
1. You can choose any DB implementation to give to Database
2. You can choose to make any Database available for remote use
None of these classes contain business logic. They are all designed for re-use. One of these design reasons made me choose singleton for Data:
Each instance of the Data class is capable of using a different database file. Supose the company creates some other database file, using the same arhcitecture (the same header schema) but different fields & values, they can do this without changing the code. All they have to do is create the database file, create a javabean Object that represents a record from that Databasefile (get/sets), add a configuration line (which binds the
java bean object with the actual data instance) somewhere and they are done.
Now, this involves multiple instances of Data, however, only ONE instance my manipulate the same database file. So, when I do
Data d1 =Data.getInstance("db1.db");
Data d2 =Data.getInstance("db2.db");
Data d3 =Data.getInstance("db1.db");
then: d1 == d3 && d1 != d2 && d2 != d3
The logic:
1. putting 'synchronized' in the signature of the read/write methods is not an option since it are object locks and not class locks. Meaning that synchronized methods can be executed at the same time over different objects.
2. synchronizing on 'this' is the same as option 1
3. synchronizing on the class was an option, but that would mean that if other instances would exist which operate on a different database file, they would wait when another instance (that could be operating on another database file) is bussy with the read/write method. This is unacceptable.
4. synchronizing on the RAF was an option, but I had to make it static, and thus I could not offer the design advantage of letting Data instances access other database files
So, in my case I only had one option left and that is implementing it as a singleton per database file.
In your case (if you do not designed it to serve other files, which if certainly no must) I think option 3 and 4 are open. Personally, I think synchronizing on the RAF would be the best choice, but I could be wrong...