I hear a lot about “Singletons are always bad” around the place. I don’t hate on them to that degree but I try not to use them if I have a better alternative.
In this case I have a system that handles a lot of requests, each of which comes in on its own thread. Every request that comes in needs to be allocated its own unique sequential Id.
Currently I have a Singleton class whose role is to initiate this Id at start-up then maintain it while the system runs. The Singleton is created/retrieved and the Id value incremented in a thread safe way, as one would expect. It is actually handed out to the threads on creation by Dependency Injection, but the core of the class is a classic Singleton built around a static representation of the current Id value.
Given that we are only likely to do more work that requires a multi-threaded approach, I would be interested to know whether there is a way I could implement this type of functionality in a way that allows data to be maintained synchronously across threads that are otherwise unaware of each other, without using the much feared Singleton pattern?
5
There is a difference between a singleton and an instance that can be shared between multiple clients. You seem to want the latter (if not, think again!). For that, a singleton has no advantage and many of the usual downsides. Just permit any number of instances, but don’t actually create several ones when you want sharing. You already have the infrastructure right for this (passing the object via dependency injection). You probably only need to make the constructor public and get rid of the singleton infrastructure.
So it costs practically nothing, and you gain:
- Simplicity: Luckily, not making something a singleton is slightly easier than making it a singleton.
- Testability: When you want to test something involving this ID allocator, you can just create a new one instead of depending on some global state of some singleton.
- Extensibility: Should you at one point need several independent sources of sequential IDs in one process, you can just create another instance.
2
By having a singleton, you’re then adding the singleton creation, access and state manipulation to your multithreading concerns.
Further, you’re assuming that your request handler is going to only have one in the entire system. This is incorrect. Yes, you might only need one now. But what about unit tests? Are you really not going to run them concurrently? What about sub-systems that may eventually want their own request dispatch? What about possibly decorating or compositing that dispatch?
No, you have some object that takes requests and assigns them an ID for that handler. If they change scopes, then you can either simply re-ID the request or have a single shared ID provider for your different request handlers.
2