单例模式

来源:互联网 发布:淘宝店铺运费模板 编辑:程序博客网 时间:2024/06/02 04:20

1.饿汉式

最容易写出来的单例模式(Singleton Pattern)。

public class Singleton {    //指向自己的私有静态引用    private static Singleton singleton = new Singleton();    //私有的构造方法    private Singleton() {    }    //返回实例    public static Singleton getInstance() {        return singleton;    }}

这种写法简单粗暴,对象在单例类被加载时就实例化了一个对象交给自己的引用,即对象在没有使用之前就已经初始化了。如果这个对象很大,没有使用这个对象之前就把它加载到内存中去不太可取。因此对其进行改进,延迟加载(Lazy-load Singleton),即懒汉式。

2.懒汉式

public class Singleton {    private static Singleton singleton = null;    private Singleton(){    }    public static Singleton getInstance() {        if(singleton == null) {            singleton = new Singleton();        }        return singleton;           }}

这种方式使用了延迟加载来保证对象在没有使用之前,是不会初始化的。但是,这种写法在多线程时会出现线程不安全。一种简单的线程安全写法如下,加锁Synchronized。

3.简单加锁

public class Singleton {    private static Singleton singleton = null;    private Singleton(){    }    public static Synchronized Singleton getInstance() {        if(singleton == null) {            singleton = new Singleton();        }        return singleton;           }}

简单加锁,会使程序的效率降低。如何既提高效率,又线程安全呢?双重检查锁方法如下(Double-Check Lock)。

4.双重检查锁

public class Singleton {    private static Singleton singleton = null;    private Singleton(){    }    public static Singleton getInstance() {        if(singleton == null) {            Synchronized(Singleton.class) {                if(singleton == null) {                    singleton = new Singleton();                }            }                   }        return singleton;           }}

这种写法做到了延迟加载、线程安全,看上去很完美,但这种写法还是有问题的。假设A线程执行到第6行,判断对象为空,于是继续执行到第9行去初始化这个对象,但初始化是需要耗费时间的,但是这个对象的地址已经存在了。此时线程B也执行到第6行,它判断不为空,于是直接跳到13行返回这个对象。但是,这个对象可能还没有被完整的初始化,得到的是一个没有完全初始化的对象。虽然这种几率很低,但也不能排除。
那么有没有更好的写法呢?静态内部类,即可以做到延迟加载,又能保证线程安全,同时不用加锁。

5.静态内部类

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

这五种方式基本已经够用,在不同的情况下选择即可。还有一种枚举的方法,由于用的少,只是记录一下。

6.枚举

public enum Singleton {    INSTANCE;    private Singleton() {    }    public Singleton getInstance() {        return INSTANCE;    } 
0 0