3

Enums are good for creating singleton. I know enum methods are not thread-safe so I tried to make it thread-safe. Can anyone please confirm if this implementation is correct or not. Is it fine to use static and volatile so many places and can it be optimized? As inner class is private so I have to create functions in enum to access inner class functionality. Can it be optimized?

import java.util.Date;

public enum SingletonWithEnum {
    INSTANCE;   

    private static class Singleton{

        private static volatile int count;
        private static volatile Date date;      

        public static  int getCount() { return count;}

        public static void setCount(int countParam) { synchronized(Singleton.class){ count = countParam; }}

        public static Date getDate() {  return date;}

        public static void setDate(Date dateParam) { synchronized(Singleton.class){ date = dateParam;}}

        public static String printObject() {
            return "Singleton [count=" + getCount() + ", date=" + getDate() + "]";
        }

    }

    public int getCount() { return Singleton.getCount();}

    public void setCount(int countParam)    {Singleton.setCount(countParam);}

    public Date getDate() { return Singleton.getDate();}

    public void setDate(Date dateParam) {Singleton.setDate(dateParam);}

    public String toString(){return Singleton.printObject();}
};

I am using it like this.

SingletonWithEnum object1 = SingletonWithEnum.INSTANCE;
object1.setCount(5);
object1.setDate(new Date());
kurochenko
  • 1,214
  • 3
  • 19
  • 43
  • 6
    "I know enum methods are not thread-safe" - well, only if you *make* them unsafe. Enums are generally stateless, at which point they're entirely thread-safe. – Jon Skeet Feb 06 '15 at 15:25
  • Using an enum here seems odd to me. They're meant to enumerate something, so this is abusing it. – Ingo Bürk Feb 06 '15 at 16:33
  • 4
    @IngoBürk it's a very common pattern to use an enum with a single instance as a singleton. In fact, enums are created only once in the JVM, so are perfect to represent singletons. See Josh Bloch's "Effective Java" for more on the topic. – Giovanni Botta Feb 06 '15 at 16:44
  • 2
    @IngoBürk For the enum singleton see http://stackoverflow.com/questions/70689/what-is-an-efficient-way-to-implement-a-singleton-pattern-in-java/16580366#16580366 –  Feb 06 '15 at 16:45
  • @JonSkeet based on this http://stackoverflow.com/questions/2531873/how-thread-safe-is-enum-in-java I considered that enum methods are not thread-safe. Did I miss something? Wow Jon u r excellent in c-sharp also. I always want to be expert in multiple languages but industry trends always push to stick with one language. How did u manage that? – Rahul Kulshreshtha Feb 07 '15 at 07:34
  • @RahulKulshreshtha: Enum methods aren't inherently safe or unsafe. There can be multiple threads calling a particular method (or different methods) at the same time, so you need to be prepared for that, e.g. using `AtomicInteger` or synchronization. But it's not like that's specific to enums - and if your enum values are immutable, as is usually the case, then you don't need to do any extra work. The issue comes from introducing mutability as you have. In that case, I'd generally discourage the singleton pattern in general. – Jon Skeet Feb 07 '15 at 07:51

1 Answers1

9

First of all, you don't need a nested class in your enum. You just need to define members and methods in the enum itself, i.e.,

enum Blah {
  INSTANCE;
  private int someField;
  public int getSomeField() { return someField; }
}

Now you can access your singleton method this way:

int someField = Blah.INSTANCE.getSomeField();

Moreover, making the members static is kind of an anti-pattern here since the singleton instance should own its members. So they should be instance variables, not static variables. The fact that there is only one instance of the singleton ensures that you only have one instance of each member in your JVM.

As far as thread safety is concerned, I personally prefer atomic variables over volatile, e.g.,

private final AtomicInteger count = new AtomicInteger();
private final AtomicReference<Date> date = new AtomicReference<>(new Date());

Notice that they must be declared final in order to be truly thread safe because the atomic variables themselves will not change, although their value could.

If you only need the operations you coded, volatile variables should work. Atomic variables offer a few more operations as opposed to their volatile counterparts, e.g., compareAndSet for Java 7 and getAndUpdate and updateAndGet for Java 8. See this for a discussion.

However you declare them (atomic/volatile) if your member variables are thread safe and their thread safety policies are independent you don't need to worry about the thready safety of methods in your singleton. If you needed for example to update the two variables atomically in one shot, then you would have to rethink the design a little and introduce appropriate locks (both when setting and getting their value).

It's very important to be very careful with the way you modify your Date object. Date is not thread safe, so I highly recommend returning a copy and replacing the instance with a copy when changes are made, i.e. (assuming you are using AtomicReference as above),

public Date getDate() { return new Date(date.get().getTime()); }
public void setDate(Date d) {
  date.set(new Date(d.getTime()));
}

Finally, I highly recommend Brian Goetz's Concurrency in Practice and Joshua Bloch's Effective Java to learn more about concurrency and singleton pattern respectively.

Community
  • 1
  • 1
Giovanni Botta
  • 9,626
  • 5
  • 51
  • 94
  • 2
    AtomicReference and AtomicInteger are exactly equivalent to the volatile equivalents unless you need compare-and-set functionality (which the example doesn't have). neither version needs synchronization at all. – jtahlborn Feb 06 '15 at 16:48
  • @jtahlborn true, but using atomic variables from the start does not hurt (in terms of performance) and makes it easy to add that functionality later on. I also usually feel like atomic variables are easier to use and to understand compared to volatile ones. – Giovanni Botta Feb 06 '15 at 16:52
  • Your answer implies that there is a gain in thread-safety when using atomics over volatile, when there isn't. – jtahlborn Feb 06 '15 at 17:06
  • @jtahlborn I believe there is because it's a lot easier to reason about atomics and they allow more complex operations, like compare-and-set as you noticed. However, I'll update my answer to reflect that it's more of a personal preference. – Giovanni Botta Feb 06 '15 at 17:11
  • 1
    @GiovanniBotta, a call to `a.set(...)` where `a` refers to an AtomicXxxxxx has exactly the same synchronization consequences as updating a `volatile` variable, and a call to `a.get()` has exactly the same consequences as reading a `volatile`, so how is the "reasoning" about them any different? – Solomon Slow Feb 06 '15 at 18:04
  • +1, especially for the book recommendations at the end. That said - "If your member variables are thread safe you don't need to worry about the thread safety of methods in your singleton" is not necessarily true - if the values of two or more individual variables need to be correlated, then the individual variables could be thread-safe but the composite behavior not be. – Sbodd Feb 06 '15 at 18:38
  • @Sbodd good points. I incorporated them in my answer and made it clear when atomic variables are really necessary. Thanks! – Giovanni Botta Feb 06 '15 at 19:07
  • Thanks for quick response. First reason why I choose my class to be inner class because I wanted to hide it so no one should be able to create it's instance without using Enum. Please let me know if there is any alternative to this. Secondly I understood I should not make it's member static, I will remove that. As "compareandset" was not required in my case so I dropped the plan to use atomic but certainly I can use that. Yes I will change getDate implementation. @Sbodd good point about composite behaviour. In my case it was not required so I dropped it, both variable are separate in my case. – Rahul Kulshreshtha Feb 07 '15 at 07:55
  • @GiovanniBotta If I see an atomic class I expect it to be there for a reason - now for such a simple class that won't be a problem but for more complicated one's this just causes confusion. If I need a map of things I won't use a OrderedMap just because it can't harm either after all. – Voo Feb 07 '15 at 08:38
  • The whole point of having an enum is so nobody can instantiate it and there can only be one instance. That's why you don't need an inner class. – Giovanni Botta Feb 07 '15 at 13:52
  • @voo as I said I personally prefer atomics. Although in this case volatile works, I believe the cases when that's true are rare like white flies. Moreover I find atomics easier to reason about which is a good enough reason to use them exclusively to me. – Giovanni Botta Feb 07 '15 at 13:53