java设计模式之单例模式5种方法及优缺点小结

来源:互联网 发布:淘宝卖家需要的软件 编辑:程序博客网 时间:2024/06/07 00:26

单例设计模式的用处。

单例设计模式是指,某个类只有一个实例。在计算机系统中类似于打印机和最常见的就是任务管理器的对话框,不管几个用户同时登录windows 打开的任务对话框只有一个。

常见的几种实现方式:

1.lazy-load

/* 适合单线程模式 延迟加载 lazy-load*/public class Singleton {    /* 私有的静态对象变量,来标记是否初始化过 也用来把实例化进行缓存*/    private static Singleton instance = null;    /* 私有的构造函数防止外部调用 */    private Singleton (){}    /* 供外部调用的接口是public的其余均为private */    public static Singleton getInstance(){        /* 单线程模式先如果对象变量为空,那么需要创建 */        /* 但是多线程下这个地方需要同步,否则会出现两个线程都创建了一个实例的情况 */        if(instance == null){            instance = new Singleton();        }        return instance;    }}

2.lazy-load的变种1线程安全了但是效率很差

/* 多线程下可以使用但是如果两个线程同时想创建实例的化,加锁和等待锁是很耗时的如果不想创建实例了但是还要获取锁,这样很不好。 lazy-load */public class Singleton{    private static Singleton instance = null;    private Singleton(){    }    public static synchronized Singleton getInstance(){        if(instance == null){            instance = new Singleton();        }        return instance;    }}

3,lazy-load的变种2线程安全了,效率有提高

/* 对上一种方式进行了优化,提前判断一下变量是否为空,前后两次判断是否存在 lazy-load *//* 但是这种两次if判断的存在出错的情况 *//*  */public class Singleton{    /* 此处使用volatile关键字 */    private volatile static Singleton instance = null;    private Singleton(){}    public static  Singleton getInstance(){        /* 第一次判断 隔绝在已经实例之后调用get接口获取实例对象的情况,放置这些情况仍然调用锁 */        if(instance == null){        /* 防止两个线程同时进行创建实例 */            synchronized(Singleton.class){            /* 这个if判断也是必须的,如果出现了两个线程同时等待锁,但是第一个线程释放之后,第二个线程进入但是却没有判断锁是否释放的化,那么仍然是创建了两次,同时这个instance也一定是volatile 的保证可见性 */                if(instance == null){                    instance = new Singleton();                }            }        }        return instance;    }}

但是这样的doubleif仍然有问题。虽然使用了volatile 虽然两次if判断。
因为无序写入:

这个double if 判断的参考了这个写的特别好,值得学习
引申:

4.饿汉式

/* 饿汉式,类加载就会创建实例而不去管你用不用, 但是内存使用率低 线程安全。因为虚拟机保证了类只会加载一次,在装载类的时候是不会并发的 */public class Singleton{    private static Singleton instance = new Singleton();    private Singleton(){}    public static Singleton getInstance(){        return instance;    }}

5.静态内部类

/* 静态内部类 *//* 由于内部类不会在加载外部类的时候进行加载,那么这个也属于lazy-load。但是这种延迟加载的加载也是class的加载jvm保证只有一次所以同样线程安全 */public class Singleton{    private Singleton(){}    private static class SingletonIneerClass{        private final static Singleton instance = new Singleton();    }    public static Singleton getInstance(){        return SingletonIneerClass.instance();    }}