Singleton with Arguments in Java

Scott picture Scott · Jun 26, 2009 · Viewed 124.8k times · Source

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!

Answer

Yuval Adam picture Yuval Adam · Jun 26, 2009

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.