线程安全的Enum Singleton [英] Thread-safe Enum Singleton

查看:119
本文介绍了线程安全的Enum Singleton的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

枚举适用于创建单身人士。我知道枚举方法不是线程安全的,所以我试着让它成为线程安全的。任何人都可以确认这种实施是否正确。是否可以使用静态和易失性这么多地方并且可以进行优化?由于内部类是私有的,因此我必须在枚举中创建函数以访问内部类功能。可以优化吗?

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();}
};

我这样使用它。

SingletonWithEnum object1 = SingletonWithEnum.INSTANCE;
object1.setCount(5);
object1.setDate(new Date());


推荐答案

首先,你不需要嵌套在你的枚举中。你只需要在枚举本身中定义成员和方法,即

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();

此外,使成员静态是一种反模式,因为单例实例应该拥有它成员。所以它们应该是实例变量,而不是静态变量。事实上只有一个单例实例确保你的JVM中只有一个每个成员的实例。

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.

就线程安全而言,我个人而言更喜欢原子变量优于volatile,例如

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());

请注意,必须声明 final 为了真正的线程安全,因为原子变量本身不会改变,尽管它们的值可以。

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.

如果你只需要编码的操作,volatile变量应该有效。与其易失性对应物相比,原子变量提供了更多操作,例如,对于Java 7, compareAndSet getAndUpdate updateAndGet for Java 8.参见这个用于讨论。

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).

非常谨慎地修改 Date 对象的方式非常重要。 日期 线程安全,所以我强烈建议您在更改时返回副本并用副本替换实例,即(假设您是使用 AtomicReference ,如上所述),

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()));
}

最后,我强烈推荐Brian Goetz的Concurrency in Practice和Joshua Bloch的Effective Java to分别了解有关并发和单例模式的更多信息。

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.

这篇关于线程安全的Enum Singleton的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆