【问题标题】:When using the singleton design pattern, do other methods need to use synchronized keyword to ensure thread safety?使用单例设计模式时,其他方法是否需要使用同步关键字来保证线程安全?
【发布时间】:2019-04-04 01:50:18
【问题描述】:

我想确保下面的类是线程安全的,我应该为其他方法使用 synchronized 关键字吗?或者使用线程安全的数据结构来存储电子邮件。我该怎么办?

public class RecycleStation {
    private static volatile RecycleStation uniqueInstance;
    private static List<Email> recycleEmailList ;

    private RecycleStation() {
        recycleEmailList = new ArrayList<>();
    }

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

    public void RecycleEmail(Email email) {
        recycleEmailList.add(email);
    }

    public void deleteEmail(Email email) {
        recycleEmailList.remove(email);
    }

    public void clear() {
        recycleEmailList.clear();
    }

}

【问题讨论】:

标签: java design-patterns singleton


【解决方案1】:

最好为您的电子邮件使用thread-safeatomic 数据结构,而不是在每个更新方法中设置synchronized。同步使用了操作系统的lock机制,这是一个昂贵的操作,应该避免。

我会使用ConcurrentLinkedQueue(下面的示例)。

关于类本身 - 用于线程安全单例的 Lazy-Initialization 设计模式也可能是一个很好的解决方案。

在您的情况下,它主要是专业人士:

  • 您避免在getInstance() 中使用synchronized
  • 略微缩短启动时间
  • 线程安全:)

编辑:查看this article 以更好地理解为什么这个实现是线程安全的。 @Rafael 提出了一个很好的观点:惰性初始化本身并不一定意味着线程安全。

说到底,这是一个实现:

public class RecycleStation  {
    private static RecycleStation uniqueInstance; //You don't need `volatile` here
    private static ConcurrentLinkedQueue<Email> recycleEmailList;

    // Here it all begins:
    private static class SingletonHolder {
        private static RecycleStation  instance = new RecycleStation();
    }
    public static RecycleStation getInstance() {
        return SingletonHolder.instance;
    }
    private RecycleStation () {
        recycleEmailList = new ConcurrentLinkedQueue<>();
    }

    // class functions:
    public void RecycleEmail(Email email) {
        recycleEmailList.add(email);
    }

    public void deleteEmail(Email email) {
        recycleEmailList.remove(email);
    }

    public void clear() {
        recycleEmailList = new ConcurrentLinkedQueue<>();
    }
}

【讨论】:

  • 你怎么能假设这是线程安全的。如果两个线程试图同时懒惰地初始化单例呢?延迟初始化和线程安全是两个不同的东西。
  • 这是一个很好的观点,我不得不对这个具体的实现做进一步的解释:SingletonHolder 类在我们引用它之前不会被加载。这意味着当我们导入RecyclerStation 类时,直到调用getInstance() 方法(引用SingletonHolder)时才会创建实例。由于只有一个线程加载类(在这种情况下仅是主线程),因此只会创建一个实例,因此 - 线程安全和延迟初始化。但如果我有任何错误,请纠正我。
  • 看看this article
  • 如果有多个线程会使用操纵email list 的函数,那怎么可能是线程安全的???
  • 另一个好点。我太专注于类初始化 - 我修正了我的答案。但是,请注意,将方法设置为 synchronized 在速度方面并不是最有效的解决方案。看看我的编辑。
【解决方案2】:

首先,a Singleton pattern is best implemented as Enum in Java 其次,每个email 操作函数(clearRecycledeleteshould be synchronized to ensure thread safety(链接是关于一个枚举,但对于每个 Sinlgeton 实现也是如此):

public synchronized void RecycleEmail(Email email)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-13
    • 2016-05-15
    • 1970-01-01
    相关资源
    最近更新 更多