I was reading the Singleton article on Wikipedia and I came across this example:
public class Singleton {
// Private constructor prevents instantiation from other classes
private Singleton() {}
/**
* SingletonHolder is loaded on the first execution of Singleton.getInstance()
* or the first access to SingletonHolder.INSTANCE, not before.
*/
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
While I really like the way this Singleton behaves, I can't see how to adapt it to incorporate arguments to the constructor. What is the preferred way to do this in Java? Would I have to do something like this?
public class Singleton
{
private static Singleton singleton = null;
private final int x;
private Singleton(int x) {
this.x = x;
}
public synchronized static Singleton getInstance(int x) {
if(singleton == null) singleton = new Singleton(x);
return singleton;
}
}
Thanks!
Edit: I think I have started a storm of controversy with my desire to use Singleton. Let me explain my motivation and hopefully someone can suggest a better idea. I am using a grid computing framework to execute tasks in parallel. In general, I have something like this:
// AbstractTask implements Serializable
public class Task extends AbstractTask
{
private final ReferenceToReallyBigObject object;
public Task(ReferenceToReallyBigObject object)
{
this.object = object;
}
public void run()
{
// Do some stuff with the object (which is immutable).
}
}
What happens is that even though I merely pass a reference to my data to all of the tasks, when the tasks are serialized, the data gets copied over and over. What I want to do is share the object among all of the tasks. Naturally, I might modify the class like so:
// AbstractTask implements Serializable
public class Task extends AbstractTask
{
private static ReferenceToReallyBigObject object = null;
private final String filePath;
public Task(String filePath)
{
this.filePath = filePath;
}
public void run()
{
synchronized(this)
{
if(object == null)
{
ObjectReader reader = new ObjectReader(filePath);
object = reader.read();
}
}
// Do some stuff with the object (which is immutable).
}
}
As you can see, even here I have the issue that passing a different file path means nothing after the first one is passed. This is why I like the idea for a store which was posted in the answers. Anyhow, rather than including the logic for loading the file in the run method, I wanted to abstract this logic into a Singleton class. I will not provide yet another example, but I hope you get the idea. Please let me hear your ideas for a more elegant way to accomplish what I am trying to do. Thank you again!
I'll make my point very clear: a singleton with parameters is not a singleton.
A singleton, by definition, is an object you want to be instantiated no more than once. If you are trying to feed parameters to the constructor, what is the point of the singleton?
You have two options. If you want your singleton to be initialized with some data, you may load it with data after instantiation, like so:
SingletonObj singleton = SingletonObj.getInstance();
singleton.init(paramA, paramB); // init the object with data
If the operation your singleton is performing is recurring, and with different parameters every time, you might as well pass the parameters to the main method being executed:
SingletonObj singleton = SingletonObj.getInstance();
singleton.doSomething(paramA, paramB); // pass parameters on execution
In any case, instantiation will always be parameter-less. Otherwise your singleton is not a singleton.
I think you need something like a factory to have objects with various parameters instantiated and reused. It could be implemented by using a synchronized HashMap
or ConcurrentHashMap
map a parameter (an Integer
for an example) to your 'singleton' parameterizable class.
Although you might get to the point where you should use regular, non-singleton classes instead (for example needing 10.000 differently parametrized singleton).
Here is an example for such store:
public final class UsefulObjFactory {
private static Map<Integer, UsefulObj> store =
new HashMap<Integer, UsefulObj>();
public static final class UsefulObj {
private UsefulObj(int parameter) {
// init
}
public void someUsefulMethod() {
// some useful operation
}
}
public static UsefulObj get(int parameter) {
synchronized (store) {
UsefulObj result = store.get(parameter);
if (result == null) {
result = new UsefulObj(parameter);
store.put(parameter, result);
}
return result;
}
}
}
To push it even further, the Java enum
s can be also considered (or used as) parametrized singletons, although allowing only a fixed number static variants.
However, if you need a distributed1 solution, consider some lateral caching solution. For example: EHCache, Terracotta, etc.
1 in the sense of spanning multiple VMs on probably multiple computers.
You can also use the Builder pattern if you want to show that some parameters are mandatory.
public enum EnumSingleton {
INSTANCE;
private String name; // Mandatory
private Double age = null; // Not Mandatory
private void build(SingletonBuilder builder) {
this.name = builder.name;
this.age = builder.age;
}
// Static getter
public static EnumSingleton getSingleton() {
return INSTANCE;
}
public void print() {
System.out.println("Name "+name + ", age: "+age);
}
public static class SingletonBuilder {
private final String name; // Mandatory
private Double age = null; // Not Mandatory
private SingletonBuilder(){
name = null;
}
SingletonBuilder(String name) {
this.name = name;
}
public SingletonBuilder age(double age) {
this.age = age;
return this;
}
public void build(){
EnumSingleton.INSTANCE.build(this);
}
}
}
Then you could create/instantiate/parametrized it as follow:
public static void main(String[] args) {
new EnumSingleton.SingletonBuilder("nico").age(41).build();
EnumSingleton.getSingleton().print();
}
You can add an initialization method in order to separate instantiation from getting.
public class Singleton {
private static Singleton singleton = null;
private final int x;
private Singleton(int x) {
this.x = x;
}
public static Singleton getInstance() {
if(singleton == null) {
throw new AssertionError("You have to call init first");
}
return singleton;
}
public synchronized static Singleton init(int x) {
if (singleton != null)
{
// in my opinion this is optional, but for the purists it ensures
// that you only ever get the same instance when you call getInstance
throw new AssertionError("You already initialized me");
}
singleton = new Singleton(x);
return singleton;
}
}
Then you can call Singleton.init(123)
once to configure it, in your app startup for example.
Use getters and setters to set the variable and make the default constructor private. Then use:
Singleton.getInstance().setX(value);
Surprised that no one mentioned how a logger is created/retrieved. For example, below shows how Log4J logger is retrieved.
// Retrieve a logger named according to the value of the name parameter. If the named logger already exists, then the existing instance will be returned. Otherwise, a new instance is created.
public static Logger getLogger(String name)
There are some levels of indirections, but the key part is below method which pretty much tells everything about how it works. It uses a hash table to store the exiting loggers and the key is derived from name. If the logger doesn't exist for a give name, it uses a factory to create the logger and then adds it to the hash table.
69 Hashtable ht;
...
258 public
259 Logger getLogger(String name, LoggerFactory factory) {
260 //System.out.println("getInstance("+name+") called.");
261 CategoryKey key = new CategoryKey(name);
262 // Synchronize to prevent write conflicts. Read conflicts (in
263 // getChainedLevel method) are possible only if variable
264 // assignments are non-atomic.
265 Logger logger;
266
267 synchronized(ht) {
268 Object o = ht.get(key);
269 if(o == null) {
270 logger = factory.makeNewLoggerInstance(name);
271 logger.setHierarchy(this);
272 ht.put(key, logger);
273 updateParents(logger);
274 return logger;
275 } else if(o instanceof Logger) {
276 return (Logger) o;
277 }
...
"A singleton with parameters is not a singleton" statement is not completely correct. We need to analyze this from the application perspective rather than from the code perspective.
We build singleton class to create a single instance of an object in one application run. By having a constructor with parameter, you can build flexibility into your code to change some attributes of your singleton object every time you run you application. This is not a violation of Singleton pattern. It looks like a violation if you see this from code perspective.
Design Patterns are there to help us write flexible and extendable code, not to hinder us writing good code.
Modification of Singleton pattern that uses Bill Pugh's initialization on demand holder idiom. This is thread safe without the overhead of specialized language constructs (i.e. volatile or synchronized):
public final class RInterfaceHL {
/**
* Private constructor prevents instantiation from other classes.
*/
private RInterfaceHL() { }
/**
* R REPL (read-evaluate-parse loop) handler.
*/
private static RMainLoopCallbacks rloopHandler = null;
/**
* SingletonHolder is loaded, and the static initializer executed,
* on the first execution of Singleton.getInstance() or the first
* access to SingletonHolder.INSTANCE, not before.
*/
private static final class SingletonHolder {
/**
* Singleton instance, with static initializer.
*/
private static final RInterfaceHL INSTANCE = initRInterfaceHL();
/**
* Initialize RInterfaceHL singleton instance using rLoopHandler from
* outer class.
*
* @return RInterfaceHL instance
*/
private static RInterfaceHL initRInterfaceHL() {
try {
return new RInterfaceHL(rloopHandler);
} catch (REngineException e) {
// a static initializer cannot throw exceptions
// but it can throw an ExceptionInInitializerError
throw new ExceptionInInitializerError(e);
}
}
/**
* Prevent instantiation.
*/
private SingletonHolder() {
}
/**
* Get singleton RInterfaceHL.
*
* @return RInterfaceHL singleton.
*/
public static RInterfaceHL getInstance() {
return SingletonHolder.INSTANCE;
}
}
/**
* Return the singleton instance of RInterfaceHL. Only the first call to
* this will establish the rloopHandler.
*
* @param rloopHandler
* R REPL handler supplied by client.
* @return RInterfaceHL singleton instance
* @throws REngineException
* if REngine cannot be created
*/
public static RInterfaceHL getInstance(RMainLoopCallbacks rloopHandler)
throws REngineException {
RInterfaceHL.rloopHandler = rloopHandler;
RInterfaceHL instance = null;
try {
instance = SingletonHolder.getInstance();
} catch (ExceptionInInitializerError e) {
// rethrow exception that occurred in the initializer
// so our caller can deal with it
Throwable exceptionInInit = e.getCause();
throw new REngineException(null, exceptionInInit.getMessage());
}
return instance;
}
/**
* org.rosuda.REngine.REngine high level R interface.
*/
private REngine rosudaEngine = null;
/**
* Construct new RInterfaceHL. Only ever gets called once by
* {@link SingletonHolder.initRInterfaceHL}.
*
* @param rloopHandler
* R REPL handler supplied by client.
* @throws REngineException
* if R cannot be loaded.
*/
private RInterfaceHL(RMainLoopCallbacks rloopHandler)
throws REngineException {
// tell Rengine code not to die if it can't
// load the JRI native DLLs. This allows
// us to catch the UnsatisfiedLinkError
// ourselves
System.setProperty("jri.ignore.ule", "yes");
rosudaEngine = new JRIEngine(new String[] { "--no-save" }, rloopHandler);
}
}
The reason you can't make sense of how to accomplish what you're trying to do is probably that what you're trying to do doesn't really make sense. You want to call getInstance(x)
with different arguments, but always return the same object? What behavior is it you want when you call getInstance(2)
and then getInstance(5)
?
If you want the same object but for its internal value to be different, which is the only way it's still a singleton, then you don't need to care about the constructor at all; you just set the value in getInstance()
on the object's way out. Of course, you understand that all your other references to the singleton now have a different internal value.
If you want getInstance(2)
and getInstance(5)
to return different objects, on the other hand, you're not using the Singleton pattern, you're using the Factory pattern.
In your example you are not using a singleton. Notice that if you do the following (assuming that the Singleton.getInstance was actually static):
Singleton obj1 = Singleton.getInstance(3);
Singleton obj2 = Singleton.getInstance(4);
Then the obj2.x's values is 3, not 4. If you need to do this, make it a plain class. If the number of values is small and fixed, you can consider using an enum
. If you are having problem with excessive object generation (which is usually not the case), then you can consider caching values (and check sources or get help with that, as it is obvious how to build caches without the danger of memory leaks).
You also might want to read this article as singletons can be very easily overused.
Another reason Singletons are an anti-pattern is that if written according to recommendations, with private constructor, they are very hard to subclass and configure to use in certain unit tests. Would be required in maintaining legacy code, for example.
If you want to create a Singleton class serving as a Context, a good way is to have a configuration file and read the parameters from the file inside instance().
If the parameters feeding the Singleton class are got dynamically during the running of your program, simply use a static HashMap storing different instances in your Singleton class to ensure that for each parameter(s), only one instance is created.
If we take the problem as "how to make singleton with state", then it is not necessary to pass the state as constructor parameter. I agree with the posts that initialize the states or using set method after getting the singleton instance.
Another question is: is it good to have singleton with state?
Couldn't we do something like this:
public class Singleton {
private int x;
// Private constructor prevents instantiation from other classes
private Singleton() {}
/**
* SingletonHolder is loaded on the first execution of Singleton.getInstance()
* or the first access to SingletonHolder.INSTANCE, not before.
*/
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(int x) {
Singleton instance = SingletonHolder.INSTANCE;
instance.x = x;
return instance;
}
}
In spite of what some may assert, here is a singleton with parameters in constructor
public class Singleton {
private static String aParameterStored;
private static final Singleton instance = new Singleton("Param to set");
private Singleton() {
// do nothing
}
private Singleton(String param) {
aParameterStored = param;
}
public static Singleton getInstance() {
return instance;
}
/*
* ... stuff you would like the singleton do
*/
}
The singleton pattern say :
- ensure that only one instance of the singleton class ever exists
- provide global access to that instance.
which are respected with this example.
Why not directly set the property ? It's textbook case to show how we can get a singleton having constructor with parameter but it could be useful in some situations. For example in inheritance cases to force the singleton to set some superclass properties.
This is not quite a singleton, but may be something that could fix your problem.
public class KamilManager {
private static KamilManager sharedInstance;
/**
* This method cannot be called before calling KamilManager constructor or else
* it will bomb out.
* @return
*/
public static KamilManager getInstanceAfterInitialized() {
if(sharedInstance == null)
throw new RuntimeException("You must instantiate KamilManager once, before calling this method");
return sharedInstance;
}
public KamilManager(Context context, KamilConfig KamilConfig) {
//Set whatever you need to set here then call:
s haredInstance = this;
}
}
I think this is a common problem. Separating the "initialization" of the singleton from the "get" of the singleton might work (this example uses a variation of double checked locking).
public class MySingleton {
private static volatile MySingleton INSTANCE;
@SuppressWarnings("UnusedAssignment")
public static void initialize(
final SomeDependency someDependency) {
MySingleton result = INSTANCE;
if (result != null) {
throw new IllegalStateException("The singleton has already "
+ "been initialized.");
}
synchronized (MySingleton.class) {
result = INSTANCE;
if (result == null) {
INSTANCE = result = new MySingleton(someDependency);
}
}
}
public static MySingleton get() {
MySingleton result = INSTANCE;
if (result == null) {
throw new IllegalStateException("The singleton has not been "
+ "initialized. You must call initialize(...) before "
+ "calling get()");
}
return result;
}
...
}
Singleton is, of course, an "anti-pattern" (assuming a definition of a static with variable state).
If you want a fixed set of immutable value objects, then enums are the way to go. For a large, possibly open-ended set of values, you can use a Repository of some form - usually based on a Map
implementation. Of course, when you are dealing with statics be careful with threading (either synchronise sufficiently widely or use a ConcurrentMap
either checking that another thread hasn't beaten you or use some form of futures).
Singletons are generally considered to be anti-patterns and shouldn't be used. They do not make code easy to test.
A singleton with an argument makes no sense anyway - what would happen if you wrote:
Singleton s = SingletonHolder.getInstance(1);
Singleton t = SingletonHolder.getInstance(2); //should probably throw IllegalStateException
Your singleton is also not thread-safe as multiple threads can make simultaneous calls to getInstance
resulting in more than one instance being created (possibly with different values of x
).
来源:https://stackoverflow.com/questions/1050991/singleton-with-arguments-in-java