<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">最近单例模式有点火,虽然还不太明白为什么,但在这里也做一个总结,顺带也检查下自己对于这个设计模式的掌握,好了,闲话不多说,直接上代码</span>
class Singleton { private Singleton(){}; private static final Singleton instance= new Singleton(); public static Singleton getInstance() { return instance; }
这是单例模式最为简单,也是最为常用的一种模式,也就是我们常说的饿汉式实现方法,体现了单例模式的所有特征(构造器私有,通过getIntance方法来获取实例,仅会在内存中构建一个真正的实例),不过这种方法也有缺点,就是每次类加载的时候,由于静态方法都要被加载,如果这个单例的实例要占用大量的资源,启动虚拟机就加载就有点得不偿失了,所以就有人想出了第二种方法,及我们常说的懒汉式方法,闲话不多说,直接上代码
class Singleton { private Singleton(){}; private static Singleton instance; public static Singleton getInstance() { if (instance==null) { instance=new Singleton(); } return instance; } }
上面就是单例模式的懒汉式实现方式,在一开始类加载的时候挂一个null的空连接,然后在使用的时候在创建一个新的对象,既可以节约资源又可以实现单例的目的,和乐而不为~
但渐渐地就有人发现这种模式的问题了,俗话说每一次优化都有可能带来新的问题,上面饿汉式在单线程环境下没有问题,但如果我是在多线程的条件下呢?两个线程一起访问getIntance方法怎么办,同时发现它是null怎么办?这不就违背了单例的初衷了么
所以就有了下面的改进版的懒汉式
public class Singleton { private static Singleton instance=null<span style="font-family: Arial, Helvetica, sans-serif;">; </span> private Singleton (){} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
这样一下就解决了,线程同步的问题,哇,好欢乐,但应用的时候在悲催的发现原来99.9999%的情况都是不需要同步的,而且奇低的效率,让人不忍直视啊,怎么办?改进呗~于是就有了懒汉式2代闪亮登场
public class Singleton { private volatile static Singleton singleton=null; private Singleton (){} public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
这也就是传说中的双重校验锁模式,不得不说想出这种模式的人,不可谓不强大,无比的纠结之心如滔滔洪水,在我的心中绵绵不绝,作者很犀利的看出了在多线程环境下,检测null操作与创建对象操作不一致的问题,它主要考虑的就是多线程的并发但我的心真的看的好纠结啊,还有没有更好的办法呢,就有了我第一次接触单例模式时想到的内部类解决方法
class Singleton { private Singleton(){}; private static class getSingletonInstance{ private static final Singleton instance = new Singleton(); } public static Singleton getInstance() { return getSingletonInstance.instance; } }
该方法,主要利用了内部类可以方便的访问外部类的成员变量就像访问自己的成员变量一样优点,因为没有静态属性,在虚拟机启动的时候并不会被初始化,知道调用getIntance方法才会产生具体的实例,而且内部类是static内部类,语义也不会允许有多个实例存在,而java规范规定类的构造必须是原子非并发的所以连getIntance()方法也都不需要加同步synchronized,一切的一切都very prefect ,所以我个人也最推荐使用静态内部类的单例实现方法,当然如果有更好的方法欢迎大家拍砖