2

我正在学习一些设计模式并发现了惊人的单例!

实现单例模式似乎有两种主要方式——一种是线程安全的(使用synchronized关键字),另一种不是线程安全的。

我的问题是,什么时候不想让他们的单例线程安全?即使最初的程序设计没有实现线程,也可能无法说明未来的迭代会有这种需求。使单例线程安全时是否存在性能损失?或者我遗漏的其他一些原因,在线程安全的单例中没有优势?

示例线程安全单例:

/**
 * Thread Safe Singleton Pattern
 *
 */
public class Database {
    private volatile static H2 uniqueInstance;

    public static H2 getInstance() {
        if (Database.uniqueInstance == null) {
            synchronized (Database.class) {
                if (Database.uniqueInstance == null) {

                    /**
                     * Instantiate First and Only instance of H2
                     */
                    Database.uniqueInstance = new H2();
                }
            }
        }
        return Database.uniqueInstance;
    }
    private Database() {};
}

示例非线程安全单例:

/**
 * Non Thread Safe Singleton Pattern
 *
 */
public class Database {
    private volatile static H2 uniqueInstance;

    public static H2 getInstance() {
        if (Database.uniqueInstance == null) {

            /**
             * Instantiate First and Only instance of H2
             */
            Database.uniqueInstance = new H2();
            }
        }
        return Database.uniqueInstance;
    }
    private Database() {};
}
4

3 回答 3

2

如果您正在编写一个您知道只有您会使用并且不涉及Threads 的程序,那么您不需要同步

如果您使用的单例是不可变的或没有可变状态,那么您也不需要使用同步

所以基本上它取决于你的目的,它的可变状态(或缺少一个)和你的单例的可能用途。

顺便说一句:这是常识,在许多情况下都是如此,而不仅仅是单例模式。

于 2013-07-16T22:55:00.503 回答
1

对于标准方法或没有集合的简单类,即使您不使用多个线程,也可以使其同步。但是,如果您正在使用列表,特别是,那么正确包装集合以使它们同步将对性能产生很大影响。

以下是有关 synchronized 关键字的性能影响的一些基本提示:

http://www.javaperformancetuning.com/tips/synchronization.shtml#REF1

于 2013-07-16T23:01:48.127 回答
0

您提供的示例不是使类线程安全,而是使其延迟初始化成为线程安全的。

在应用服务器环境中,显然任何单例资源都需要容忍并发使用,但您可以保证服务启动期间的初始化将由单个线程执行。要问自己的问题实际上是“这个实例是否需要延迟初始化,或者我可以在应用程序启动期间创建它吗?” 除了更快的部署时间之外,延迟分配 100% 服务请求所需的资源并没有太多的优点。

于 2013-07-16T23:02:57.293 回答