2

There is something wrong with my code below. I am getting multiple instances of the same singleton class when calling it from multiple threads from the same process. I am expecting the program should print "Creating instance" only once but it is printing 3 times(i.e. per thread).

package SingleTon;

class SingleTon implements Runnable {
    String name;
    int salary;
    private static SingleTon singleTonInstance;

    SingleTon() {

    }

    public static SingleTon getInstance() {
        if (singleTonInstance == null) {
            synchronized (SingleTon.class) {
                System.out.println("Creating instance");
                singleTonInstance = new SingleTon();
            }
        }
        return singleTonInstance;
    }

    @Override
    public void run() {
        System.out.format("Thread %s is starting\n",Thread.currentThread().getName());
        getInstance();
    }

}

package SingleTon;

public class SingleTonDemo {

    public static void main(String[] args) {
        System.out.println("test");
        SingleTon t = new SingleTon();
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        t1.start();
        t2.start();
        t3.start();
    }

}

Output:

test
Thread Thread-0 is starting
Thread Thread-2 is starting
Thread Thread-1 is starting
Creating instance
Creating instance
Creating instance
techi
  • 133
  • 2
  • 15

5 Answers5

5

You need to change the following:

1) Make your default constructor private. As written, it is package-private and can be called by other classes in the same package.

private SingleTon() {
}

Once you have done this, your SingleTonDemo class will no longer be able to call the constructor and will be forced to use the getInstance() method. Currently, each call to the constructor is creating a new instance.

2) Synchronize the entire getInstance() method. As written, 2 separate threads can get a null value for singleTonInstance, and thus each thread would create a new instance.

    public static SingleTon getInstance() {

2a) An alternate approach to ensuring there is only one instance of the class is to use static initialization. In the declaration of the static variable, you create the object:

private static SingleTon singleTonInstance = new SingleTon();

The JVM will ensure that this is called only one. That also improves your getInstance method as you would change it to:

public static SingleTon getInstance() {
    return singleTonInstance;
}

The advantage of this approach is that not only is the getInstance method simpler, it also does not incur the overhead of being synchronized.

EJK
  • 12,332
  • 3
  • 38
  • 55
  • Thanks @EJK for your reply. But I would like to understand further, yes I will make it private agreed. But let say two threads enter the if block and then there is synchronized (SingleTon.class) , so two threads should not enter to create the instance right? – techi Jan 30 '19 at 00:40
  • If you synchronize the method, then the calling thread must acquire the class-level lock before it is able to make the call. That ensures that the first thread will be able to create the initial instance before any subsequent thread can enter the method. Subsequent threads will then see a non-null instance and thus the conditional prevents other threads from creating more instances. – EJK Jan 30 '19 at 00:44
  • It worked this way as you suggested. 1) private constructor and 2) SingleTon t = SingleTon.getInstance(); in my Demo class. I did not change anything in singleton method . – techi Jan 30 '19 at 00:45
  • I am sure it will work 99.99% of the time if you skip step 2, however in a long running multi-threaded program there is the possibility that eventually the timing will align just right (or wrong for you) which would trigger the 2nd creation. Step 2 makes your code 100% bullet-proof. – EJK Jan 30 '19 at 00:47
  • I see, just one more thing. once the thread is inside method means it will not get the value which is already written by the previous thread? Sorry I am learning them – techi Jan 30 '19 at 00:50
  • That static instance can be read by all threads. However when you synchronize the getInstance method (which is the one and only method that can create the instance), that guarantees that only one thread can be in the method at one time thus guaranteeing that exactly one instance is created. Not sure if that answers your question or not. – EJK Jan 30 '19 at 00:53
  • @techi, inside of which method? do u know what `synchronized` does? When you use a `synchronized` block, internally Java uses a monitor also known as **monitor lock** or **intrinsic lock**, to provide synchronization. These monitors are bound to an object, thus all synchronized blocks of the same object can have only **ONE** thread executing them at the same time. So if a value is already written by the previous thread the next thread will have access to it. – Teocci Jan 30 '19 at 01:29
2

You are actually creating an instance of your SingleTon class outside of the class. This should not be done when using the singleton pattern, as only a single instance of the class should be able to be created.

For the synchronization issue:

If all three threads enter the if statement in your getInstance method, every thread will create an instance (as the if statement itself is not covered by the synchronized block). One way to solve this is to make the getInstance method synchronized, i.e. adding the synchronized modifier. In that case, the fetch-and-create-if-not-exists logic in your getInstance method is executed as an atomic block.

  • Thanks for your reply. But I have synchronized (SingleTon.class) {, so why is not synchronized? – techi Jan 30 '19 at 00:38
  • Your synchronized block only starts inside the if statement. Take this possible example with two threads, A and B. Thread A checks the static variable: Does not exist. Thread B checks the static variable: Does not exist. A creates the instance and stores it. Afterwards (because of the synchronization) B creates the instance and stores it. The point is, the threads can stop *before* the synchronized block. The block will then be executed by both threads without further checks. – Yannick Buehler Jan 30 '19 at 00:40
  • Helped me understand in depth! Excellent – techi Jan 30 '19 at 00:53
0

The Answer by EJK looks correct.

Here is an alternative, simpler approach entirely.

Enum

Generally speaking, the best way to implement a Singleton in Java is making an enum. The enum facility in Java is much more powerful and flexible than in most platforms; see Tutorial.

An enum in Java is actually a subclass of Enum, with the compiler/JVM handling that behind the curtains. When your enum class is loaded, the JVM automatically instantiates an object for each of your enum names. In the case of a singleton, of course, we have only one such enum name. Commonly this one name is INSTANCE but can be anything you desire.

Because an enum in Java is actually a class, you can define a constructor and pass objects to that constructor. In our example below, we pass an initial value for the name and salary members you used in your Question.

Similarly, as a class, an enum in Java can have methods. In our example below, we added a method run to implement Runnable, just as you did in your Question.

In the example here, we added a UUID value as an identifier as another way for you to see that indeed we have only a single instance of our singleton.

package work.basil.example;

import java.time.Instant;
import java.util.UUID;

public enum SingletonDemo implements Runnable {
    INSTANCE( "Alice" , 10_000 );

    String name;
    Integer salary;
    UUID uuid;

    SingletonDemo ( String name , Integer salary ) {
        System.out.println( "DEBUG - Constructing `SingletonDemo` enum at " + Instant.now() );
        this.name = name;
        this.salary = salary;
        this.uuid = UUID.randomUUID();
    }

    @Override
    public void run () {
        // CAUTION: Be sure you make this method thread-safe!
        System.out.format( "Thread %s is starting. uuid: %s\n" , Thread.currentThread().getName() ,this.uuid.toString() ); // Calling getters as I did here may not be thread-safe without further precautions (synchronization, etc.).
    }

    public static void main ( String[] args ) {
        Thread t1 = new Thread( SingletonDemo.INSTANCE );
        Thread t2 = new Thread( SingletonDemo.INSTANCE );
        Thread t3 = new Thread( SingletonDemo.INSTANCE );
        t1.start();
        t2.start();
        t3.start();
    }
}

When run.

DEBUG - Constructing SingletonDemo enum at 2019-01-30T00:48:46.614462Z

Thread Thread-0 is starting. uuid: a2825344-fb15-45d1-a6e4-239fc3bdf3c5

Thread Thread-2 is starting. uuid: a2825344-fb15-45d1-a6e4-239fc3bdf3c5

Thread Thread-1 is starting. uuid: a2825344-fb15-45d1-a6e4-239fc3bdf3c5

Community
  • 1
  • 1
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • Impressive! I know basics of enum but not used it extensively in Java. Used it only when there is a need to define custom enum types and not for this kind of purpose. Since it is enum class, do any other operations such as serializable, the clone operations will work in real-time? sorry this is not relevant to my question in this post – techi Jan 30 '19 at 01:03
  • I am not aware of any restrictions to an enum. It is a regular class in most every respect. The only reason I know to *not* use this approach to your singleton is if you must inherit from a class. An enum in Java is already a subclass of `Enum` class, and in Java we can have only a single-line of inheritance. However, you can implement interfaces, as we implemented `Runnable` here. Search Stack Overflow and the internet to learn more, as using an enum for singleton in Java is quite common. – Basil Bourque Jan 30 '19 at 01:06
  • Ok thanks, @Basil Bourque. Appreciate your help and time – techi Jan 30 '19 at 01:15
0
public class SingleTonDemo {

public static void main(String[] args) {
    System.out.println("test");
    SingleTon t = SingleTon.getInstance();
    Thread t1 = new Thread(t);
    Thread t2 = new Thread(t);
    Thread t3 = new Thread(t);
    t1.start();
    t2.start();
    t3.start();
}

}

private SingleTon() {

}
B.hl
  • 15
  • 3
-1

First your singleton constructor MUST BE private. Second, use an object as a mutex to prevent collisions.

public class RunnableSingleton implements Runnable
{
    private static volatile RunnableSingleton instance;
    private static final Object mutex = new Object();

    private RunnableSingleton() {}

    public static RunnableSingleton getInstance()
    {
        RunnableSingleton result = instance;
        if (result == null) {
            synchronized (mutex) {
                result = instance;
                if (result == null) {
                    System.out.println("Creating instance");
                    instance = result = new RunnableSingleton();
                }
            }
        }

        return result;
    }

    @Override
    public void run()
    {
        System.out.format("Thread %s is starting\n", Thread.currentThread().getName());
        getInstance();
    }
}

Now, call the getInstance() method in your main like this:

public class SingletonDemo
{
    public static void main(String[] args) {
        System.out.println("test");
        RunnableSingleton t = RunnableSingleton.getInstance();
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        t1.start();
        t2.start();
        t3.start();
    }
}

This is the output of the implementation:

test
Creating instance
Thread Thread-0 is starting
Thread Thread-2 is starting
Thread Thread-1 is starting
Teocci
  • 7,189
  • 1
  • 50
  • 48
  • Thanks for taking the time to write a program for me!. One question to understand private static final Object mutex = new Object(); so each object has to acquire the lock on this object before it enters to create the object. I am guessing you have implemented double-checked locking for a singleton? – techi Jan 30 '19 at 00:56
  • First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object. S, you have 1 variables no-interleaved. So you want to access it from different threads at the same time. you need to define the lock not on the object class itself but on the class Object. That is basic singleton definition. – Teocci Jan 30 '19 at 01:07
  • I agree. your code is working without any issues. I did not downvote. whoever done so please explain. But I can accept only one answer. – techi Jan 30 '19 at 01:14