您的位置:首页 > 编程语言 > Java开发

java中单例模式的几种写法

2017-05-14 11:00 489 查看

什么是单例模式

单例模式是使用的最广泛的设计模式之一,用来确保一个类对外只提供唯一的实例,比如连接池、缓存、日志对象的实现基本都用的单例模式。实现单例的方法主要有以下几种,每种都有各自的优缺点,为了实现真正的单例,我们可以根据实际需求,选择合适的方法。

1. 饿汉模式

public class Singleton {
private static Singleton instance = new Singleton();

private Singleton() {}

public static Singleton getInstance() {
return instance;
}
}


优点: 简单,线程安全

缺点: 不能延时加载

推荐指数: 4星

说明: 类初始化时就加载静态变量,创建了实例,不存在多线程问题,缺点是不能在实际使用的时候才创建对象

2. 懒汉模式

线程不安全

public class Singleton {
private static Singleton instance;
private Singleton() {}

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


优点: 延迟加载

缺点:线程不安全

推荐指数: 2星

说明:在多线程环境下,很可能产生多个实例。

线程安全

public class Singleton {
private static Singleton instance;
private Singleton() {}

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


优点: 延迟加载,线程安全

缺点:性能较低

推荐指数: 3星

说明:保证了线程安全,但是由于是直接对方法进行同步,会降低性能,实际上只有在初次调用此方法时,才需要加锁来确保线程安全,一旦设置好instance实例之后,就不需再同步该方法了,也就是说,除了第一次,以后每次调用该方法,同步都是多余的

3. 双重检查锁(DCL)

public class Singleton {
private volatile static Singleton instance;//volatile可防止指令重排
private Singleton() {}

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


优点: 延迟加载,线程安全,性能较高

缺点:较为繁琐,不适用于jdk1.5以下的版本

推荐指数: 4星

说明:该方法是对懒汉模式的改进,既保证了线程安全,又不是对整个方法进行同步,对性能基本没有什么影响。不足之处是需要使用volatile关键字来保证可靠性,只能在jdk1.5及以上的版本使用,因为在jdk1.5以下版本,对于volatile关键字的实现会导致DCL的失效,具体可以参考这篇文章:Java 并发编程:volatile的使用及其原理

4. 枚举

public enum Singleton {
INSTANCE;

public void doSomething() {}
}


优点:代码简洁, 线程安全

缺点:非延迟加载

推荐指数: 5星

说明:通过枚举方式来创建单例是《Effective Java》作者Joshua Bloch大力推荐的,因为它有以下几点优势:

1. 无法通过反射调用创建实例,而在其他类型中,即使是私有方法,也能通过反射,创建新的实例。查看 java.lang.reflect.Constructor的newInstance()方法中有如下代码,说明枚举类型是禁止了通过反射构造枚举对象的

if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively      create enum objects");


2.可以有效的防止反序列化,以下是java.lang.Enum类的代码,可以看出,enum类型无法被反序列化

private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException {
throw new InvalidObjectException("can't deserialize enum");
}

private void readObjectNoData() throws ObjectStreamException {
throw new InvalidObjectException("can't deserialize enum");
}


3 枚举实例无法被克隆,以下是java.lang.Enum代码,如果要强行进行clone,直接抛出异常

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


5. 静态内部类

public class Singleton{
private Singleton(){}

public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder{
private static Singleton INSTANCE = new Singleton();
}
}


优点: 线程安全,延迟加载

缺点:

推荐指数: 5星

说明:该方式也称为IoDH( Initialization Demand Holder),可以说是结合了饿汉模式和懒汉模式的优点,既实现了延迟加载,也保证了线程安全,建议优先采用该方式创建单例。

参考:

1. wiki-单例模式

2. 单例模式方法大全

3. 单例模式的七种写法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息