在Java中实现单例设计模式的有效方法是什么?


当前回答

如果您不需要延迟加载,那么只需尝试:

public class Singleton {
    private final static Singleton INSTANCE = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() { return Singleton.INSTANCE; }

    protected Object clone() {
        throw new CloneNotSupportedException();
    }
}

如果您希望延迟加载并且希望单例是线程安全的,请尝试双重检查模式:

public class Singleton {
    private static Singleton instance = null;

    private Singleton() {}

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

    protected Object clone() {
        throw new CloneNotSupportedException();
    }
}

由于双重检查模式不能保证有效(由于编译器的一些问题,我对此一无所知),因此您也可以尝试同步整个getInstance方法或为所有单例创建注册表。

其他回答

版本1:

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

延迟加载,线程安全,阻塞,由于同步,性能低下。

版本2:

public class MySingleton {
    private MySingleton() {}
    private static class MySingletonHolder {
        public final static MySingleton instance = new MySingleton();
    }
    public static MySingleton getInstance() {
        return MySingletonHolder.instance;
    }
}

延迟加载,线程安全,无阻塞,高性能。

使用枚举:

public enum Foo {
    INSTANCE;
}

乔舒亚·布洛赫(Joshua Bloch)在Google I/O 2008的“有效Java重载”演讲中解释了这种方法:视频链接。另请参见其演示文稿的幻灯片30-32(effecte_java_reloaded.pdf):

实现可串行化Singleton的正确方法公共枚举Elvis{实例;private final String[]收藏夹歌曲={“猎犬”,“心碎酒店”};public void printFavorites(){System.out.println(Arrays.toString(收藏夹歌曲));}}

编辑:“有效Java”的在线部分说:

“这种方法在功能上等同于公共字段方法,只是它更加简洁,免费提供了序列化机制,并且即使在复杂的序列化或反射攻击的情况下也能提供针对多个实例化的铁腕保证。虽然这种方法尚未被广泛采用,但单个元素枚举类型是实现一个公共字段的最佳方式。”英格顿。"

创建单例对象的各种方法:

根据约书亚·布洛赫的说法,埃努姆将是最好的。也可以使用双重检查锁定。甚至可以使用内部静态类。

以下是三种不同的方法

枚举/***使用Java Enum的Singleton模式示例*/公共枚举EasySingleton{实例;}双重检查锁定/延迟加载/***带有双重检查锁定的单线模式示例*/公共类DoubleCheckedLockingSingleton{私有静态易失性DoubleCheckedLockingSingleton INSTANCE;private DoubleCheckedLockingSingleton(){}公共静态DoubleCheckedLockingSingleton getInstance(){如果(INSTANCE==null){synchronized(DoubleCheckedLockingSingleton.class){//双重检查Singleton实例如果(INSTANCE==null){INSTANCE=新的DoubleCheckedLockingSingleton();}}}返回INSTANCE;}}静态工厂方法/***带有静态工厂方法的Singleton模式示例*/公开课Singleton{//在类加载期间初始化private static final Singleton INSTANCE=new Singleton();//防止创建另一个“Singleton”实例私有Singleton(){}公共静态Singleton getSingleton(){返回INSTANCE;}}

确保你真的需要它。在谷歌上搜索“singleton反模式”,看看反对它的一些论点。

我想这并没有什么本质上的问题,但它只是一种公开某些全局资源/数据的机制,因此请确保这是最好的方法。特别是,我发现依赖注入(DI)更有用,特别是如果您也在使用单元测试,因为DI允许您将模拟资源用于测试目的。