简体   繁体   中英

Is this singleton pattern thread safe?

I have a singleton server instance and I'm curious whether my code is thread safe. I've read about different singleton patterns, and I think the way to go generally is the double-checked locking pattern, which goes as follows:

public static Singleton getInstance() {
    if(singleton == null) {
        synchronized(Singleton.class) {
            if(singleton == null) {
                singleton = new Singleton();
            }
        }
    }
    return singleton;
}

This is supposedly an efficient thread-safe way of setting/getting a singleton. The easiest way to get and set a singleton, I've read, is lazy instantiation , which looks like this:

public static ClassicSingleton getInstance() {
    if(instance == null) {
        instance = new ClassicSingleton();
     }
     return instance;
}

Now what I want to know is if my variation is thread-safe. My code:

public static void startServer(int listeningPortNumber) throws IOException {
    if (server != null) {
        throw new IOException("Connection exists");
    }

    server = new Server(listeningPortNumber);
}

My code is very similar to the lazy instantiation pattern above, but I can't see how my code isn't thread-safe. Is there something I'm not seeing or is this actually valid code?


Reference: http://www.javaworld.com/article/2073352/core-java/simply-singleton.html

It's not safe.

Imagine what happens if two threads call startServer at the same time (or close enough to it):

  1. Thread A checks server != null , and sees that server is null -- so it doesn't throw an exception
  2. Thread B does the same
  3. Thread A now instantiates new Server(listeningPortNumber);
  4. Thread B does the same, and presumably bad things happen at this second instantiation

If server isn't volatile , the problem is even worse, since you don't even need the interleaving anymore -- it's possible that Thread A instantiates the new Server(...) , but that the write to the server field isn't seen by Thread B for a long time (possibly forever) because it's not flushed to main memory.

But the method is racy even if server is volatile , because of the interleaving.

No, lazy singleton pattern is not thread safe.

If you want a thread-safe version of the Singleton pattern in Java, you should implement Bill Pugh's solution. The code is here:

public class OptimalSingleton
{
  protected OptimalSingleton()
  {
    // ...
  }

  private static class SingletonHolder
  {
    private final static OptimalSingleton INSTANCE = new OptimalSingleton();
  }

  public static OptimalSingleton getInstance()
  {
    return SingletonHolder.INSTANCE;
  }
}

More about it on SO: Singleton pattern (Bill Pugh's solution)

Your code is not thread safe.

Suppose you have two threads, A and B that call startServer(...) , and that prior to these calls the server has not been initialized. A passes one value (a) and B passes another (b) to the method. The only thing you know is that within each thread the order of operations is defined.

So the following is possible:

A: check server != null  (false)
B: check server != null  (false)
A: server = new Server(a)
B: server = new Server(b)

Clearly this violates the singleton. Thread A will see a server that's initialized to a value different to the one passed in, and an exception was never thrown.

Your code isn't thread safe! Suppose 2 different threads simultaneously call startServer method Both see the server variable is null so will skip the if block And each thread creating an instance of Server! So you will end with 2 instance of a server in your application.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM