java中单例模式的几种写法

来源:互联网 发布:网络歌手樊棋照片 编辑:程序博客网 时间:2024/06/05 10:29

什么是单例模式

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

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. 单例模式的七种写法

0 0
原创粉丝点击