-
定义
单例模式指的是一个类,在全局范围内(整个系统中)有且只能有一个实例存在。即该类本身负责提供一种访问其唯一对象的方式,不对外提供公共的构造函数(禁用默认公共构造函数),对于该类的实例化由它自己在类的内部进行维护!
-
优缺点
-
优点
-
最大程度的减少了对象的创建和销毁的次数,从而降低的垃圾回收的次数
-
节约了系统资源,尤其是内存资源
-
-
缺点
-
不能继承,不能被外部实例化
-
类干预了外部类的使用(外部实用类不能随意实例化),而不再仅仅专注于内部的逻辑(与单一职责模式有矛盾)
-
-
-
使用场景
-
有频繁的实例化后又销毁的情况,适合考虑使用单例模式,如记录日志的log对象
-
创建对象需要消耗过多的系统资源,但又经常用到的资源,如数据库连接
-
-
框架中的应用
-
spring框架中的Bean默认都是单例的
-
-
实现方式
单例模式有多种实现方式,要考虑到多线程下的安全性,其每种实现方式如下所示:
-
懒加载(线程不安全)
public class SingletonPattern { private static SingletonPattern instance; private SingletonPattern(){} public static SingletonPattern getInstance(){ if (instance == null){ instance = new SingletonPattern(); } return instance; } }
以上方式,如果存在多个线程同时访问getInstance()时,由于没有锁机制,会导致实例化出现两个实例的情况,因此,在多线程环境下时不安全的。
-
懒加载(线程安全)
public class SingletonPattern { private static SingletonPattern instance; private SingletonPattern(){} public static synchronized SingletonPattern getInstance(){ if (instance == null){ instance = new SingletonPattern(); } return instance; } }
如上代码所示,在getInstance()方法上添加了同步锁。但是该方法虽然解决了线程安全的问题,但却也带来了另外的一个问题,就是每次获取对象时,都要先获取锁,并发性能很差,还需要继续优化!
-
双重校验(线程安全)
public class SingletonPattern { private static SingletonPattern instance; private SingletonPattern(){} public static SingletonPattern getInstance(){ if (instance == null){ synchronized (SingletonPattern.class){ instance = new SingletonPattern(); } } return instance; } }
该方法将方法上的锁去掉了,避免了每次调用该方法都要获取锁的操作,从而提升了并发性能,同时在方法内部使用锁,进而解决了并发的问题,从而解决了上面并发安全+性能低效的问题,是个不错的实现单例的方式。
-
饿汉式(线程安全)
public class SingletonPattern { private static SingletonPattern instance = new SingletonPattern(); private SingletonPattern(){} public static SingletonPattern getInstance(){ return instance; } }
该方式虽然简单也安全,但是会造成再不需要实例时,产生垃圾对象,造成资源狼粪,因此,一般不使用。
-
内部静态类(线程安全)
public class SingletonPattern { private static class SingletonPatternHolder{ public static SingletonPattern instance = new SingletonPattern(); } private SingletonPattern(){} public static SingletonPattern getInstance(){ return SingletonPatternHolder.instance; } }
这种方式可以达到跟双重校验锁一样的效果,但只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用
-
枚举(线程安全)
public enum SingletonPattern { INSTANCE; public static SingletonPattern getInstance(){ return INSTANCE; } }
这是实现单例模式的最佳方法,更加简洁,自动支持序列化,杜绝防止多次实例化,非常高效!(强烈推荐使用)
-
-
引用