1

I have a singleton class that contains a hahsmap, the hashmap is initialised as a class variable. This map is updated correctly because when i add and print the size it changed, but, when i call it from a different thread the map is always empty. Is there a particular reason why this might happen?

I am using a ConccurentHashMap if this makes any difference.

Thanks

Singleton decleration:

    public class ClientRegistryDetailsSingleton {

        private static ClientRegistryDetailsSingleton instance = null;
        private ConcurrentHashMap<String, Integer> tickerToNumberRegistered = new ConcurrentHashMap<String,Integer>();


        protected ClientRegistryDetailsSingleton() {
             // Exists only to defeat instantiation.
        }

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

        public void setTickerToNumberRegistered(ConcurrentHashMap<String, Integer> tickerToNumberRegistered) {
            this.tickerToNumberRegistered = tickerToNumberRegistered;
        }

        public ConcurrentHashMap<String, Integer> getTickerToNumberRegistered() {
            return tickerToNumberRegistered;
        }


    public void addToClienets(String ticker){}

    public void removeFromClients(String ticker){}
}

Calling it from another thread:

String[] splitForTicker = message.split(",");

        ConcurrentHashMap<String, Integer> map = ClientRegistryDetailsSingleton.getInstance().getTickerToNumberRegistered();
        System.out.println("The number of items in the map from senders persepctive" + map.size());

Output:

The number of items in the map from senders persepctive 0
2012-11-12 14:29:12,495 [Process messages received] INFO  com.feed.feedReceive.ProcessFeedStreamLine - Successfully received a message from the feed
The number of items in the map from senders persepctive 0
1 :the size of the map now someone has added
2012-11-12 14:29:15,495 [Process messages received] INFO  com.feed.feedReceive.ProcessFeedStreamLine - Successfully received a

message from the feed The number of items in the map from senders persepctive 0

New code for Singleton

public class ClientRegistryDetailsSingleton {

    private static ClientRegistryDetailsSingleton instance = new ClientRegistryDetailsSingleton();
    private volatile ConcurrentHashMap<String, Integer> tickerToNumberRegistered = new ConcurrentHashMap<String,Integer>();

    protected ClientRegistryDetailsSingleton() {
         // Exists only to defeat instantiation.
    }

    public static synchronized ClientRegistryDetailsSingleton getInstance() {
        return instance;
    }

    public synchronized ConcurrentHashMap<String, Integer> getTickerToNumberRegistered() {
        return tickerToNumberRegistered;
    }

    public void addToClienets(String ticker){}

    public void removeFromClients(String ticker){}
}
Biscuit128
  • 5,218
  • 22
  • 89
  • 149

3 Answers3

3

There is a race condition in the posted code that can result in more that one instance of the singleton being constructed if two threads call getInstance() and the singleton has not yet been constructed:

public static ClientRegistryDetailsSingleton getInstance() {
    if(instance == null) {                                   // Line 1
        instance = new ClientRegistryDetailsSingleton();     // Line 2
    }
}

A possible execution of two threads, T1 and T2:

  • T1 peforms check at line 1 and enters if branch.
  • T1 is suspended, with instance still being null.
  • T2 peforms check at line 1 and enters if branch.
  • T2 constructs class and assigns to instance.
  • T2 returns instance to caller.
  • T2 is suspended.
  • T1 is started again and constructs another instance and assigns to instance.

The construction of the single instance must be threadsafe. Possible solutions would be:

  • Make the getInstance() method synchronized.
  • Don't use lazy initialization (if possible):

    private static final ClientRegistryDetailsSingleton instance =
        new ClientRegistryDetailsSingleton();
    
hmjd
  • 120,187
  • 20
  • 207
  • 252
  • @SkyR, apology unrequired. Just to be sure, you definitely performed a rebuild and are executing the new application? – hmjd Nov 12 '12 at 14:26
  • Yes - just did a clean, refresh and rebuild to make sure! ive just put some code output in to the original message – Biscuit128 Nov 12 '12 at 14:29
  • it must be the same instance that is being used becausei created a random int in there and then printed this from two differenct threads and it prints the same number – Biscuit128 Nov 12 '12 at 14:46
  • @SkyR, from the code it looks as though the internal map can be replaced. Is it possible the two threads are actually accessing different maps because of a swap? BTW, the member `tickerToNumberRegistered` needs to be marked `volatile` if it can be reassigned to ensure the assignment is visible to other threads. – hmjd Nov 12 '12 at 14:46
  • Hi, thanks for taking the time to help. I have already added volatile key word to the variable and also the setter has been removed. it was not needed i just accidentally created it via the eclipse wizard. – Biscuit128 Nov 12 '12 at 14:51
  • @SkyR, could you add your new code to the question (don't replace the original code as that will confuse anyone coming to the question) or uploaded somewhere else (pastebin or ideone for example)? I am unsure what the cause is. – hmjd Nov 12 '12 at 14:56
  • hmjd - i have added my most recent singleton class – Biscuit128 Nov 12 '12 at 15:01
  • I have also not mentioned that two classes sub class this class and they are both generated by Java Spring – Biscuit128 Nov 12 '12 at 15:03
  • @SkyR in Spring, singletons are beans residing in the container, typically they are not *Java* singletons. So basically they are just thread-safe objects. – Boris Treukhov Nov 12 '12 at 15:09
  • @BorisTreukhov could this be the problem then? – Biscuit128 Nov 12 '12 at 15:11
  • @SkyR it has nothing to do with the problem, this will be significant when you will add them to the container – Boris Treukhov Nov 12 '12 at 15:12
  • ok it works if i make the variable public and static :) maybe it will work if i just make it static – Biscuit128 Nov 12 '12 at 15:16
  • @SkyR Spring beans are already singletons(as there is typically only one bean instance of desired type in the container) - it's absolutely useless to implement singleton pattern for them. What you likely need is just a simple thread-safe class. I.e. without static fields at all. – Boris Treukhov Nov 12 '12 at 15:19
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/19436/discussion-between-boris-treukhov-and-skyr) – Boris Treukhov Nov 12 '12 at 15:21
0

Define your hash map as

private volatile ConcurrentHashMap<String, Integer>

The volatile keyword warns the JVM that the state of the variable may be changed by another thread at any time, so it must not be cached locally.

Defining the instance also as volatile might also be necessary.

Philipp
  • 67,764
  • 9
  • 118
  • 153
  • 1- volatile will only make changes to tickerToNumberRegistered trigger reconciling cpu cache with main memory but changes to the map itself won't do that 2- ConcurrentHashMap itself is responsible of making changes visible to all threads accessing it. – Yazan Jaber Nov 12 '12 at 14:41
  • the problem with this code is not that the changes with the map will not be synchronized - that is not the case. The problem is that the map still can be initialized twice as shown in @hmjd answer - so basically the users will see different instances of the registry and data will be lost. – Boris Treukhov Nov 12 '12 at 14:45
0

Implementation of DCL antipattern: http://en.wikipedia.org/wiki/Double_checked_locking

public class ClientRegistryDetailsSingleton {

    private static volatile ClientRegistryDetailsSingleton instance = null;

    private final ConcurrentHashMap<String, Integer> tickerToNumberRegistered = new ConcurrentHashMap<String,Integer>();


    private ClientRegistryDetailsSingleton() {
         // Exists only to defeat instantiation. 
         // please not that constructor should be private
    }

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

    //You should not break encapsulation and allow a link to HashMap escape
    private void setTickerToNumberRegistered(ConcurrentHashMap<String, Integer> tickerToNumberRegistered) {
        this.tickerToNumberRegistered = tickerToNumberRegistered;
    }

    //You should not break encapsulation and allow a link to HashMap escape
    private ConcurrentHashMap<String, Integer> getTickerToNumberRegistered() {
    }

     //I omitted the access to the hash map it's likely that some additional params required
     public void addToClienets(String ticker){}

     //I omitted the access to the hash map it's likely some additional params are required
     public void removeFromClients(String ticker){}
}

I've shown this only as a synchronization example, in real life you should likely implement your singletons as Enums : What is the best approach for using an Enum as a singleton in Java?

Community
  • 1
  • 1
Boris Treukhov
  • 17,493
  • 9
  • 70
  • 91