微信搜索:码农StayUp
主页地址:https://gozhuyinglong.github.io
源码分享:https://github.com/gozhuyinglong/blog-demosjava
单例模式(Singleton Pattern)是一种简单的对象建立型模式。该模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。git
因此要实现单例模式,要作到如下几点:github
对于单例模式有如下5种实现。安全
该方式是使用synchronized
关键字进行加锁,保证了线程安全性。
优势:在第一次调用才初始化,避免了内存浪费。
缺点:对获取实例方法加锁,大大下降了并发效率。微信
因为加了锁,对性能影响较大,不推荐使用。多线程
public class SingletonLazy { /** * 私有实例 */ private static SingletonLazy instance; /** * 私有构造方法 */ private SingletonLazy() { } /** * 惟一公开获取实例的方法(静态工厂方法),该方法使用synchronized加锁,来保证线程安全性 * * @return */ public static synchronized SingletonLazy getInstance() { if (instance == null) { instance = new SingletonLazy(); } return instance; } }
饿汉式是利用类加载机制来避免了多线程的同步问题,因此是线程安全的。
优势:未加锁,执行效率高。
缺点:类加载时就初始化实例,形成内存浪费。并发
若是对内存要求不高的状况,仍是比较推荐使用这种方式。性能
public class SingletonEager { /** * 私有实例,静态变量会在类加载的时候初始化,是线程安全的 */ private static final SingletonEager instance = new SingletonEager(); /** * 私有构造方法 */ private SingletonEager() { } /** * 惟一公开获取实例的方法(静态工厂方法) * * @return */ public static SingletonEager getInstance() { return instance; } }
利用了volatile修饰符的线程可见性(被一个线程修改后,其余线程当即可见),即保证了懒加载,又保证了高性能,因此推荐使用。编码
public class SingletonDCL { /** * 私有实例,volatile修饰的变量是具备可见性的(即被一个线程修改后,其余线程当即可见) */ private volatile static SingletonDCL instance; /** * 私有构造方法 */ private SingletonDCL() { } /** * 惟一公开获取实例的方法(静态工厂方法) * * @return */ public static SingletonDCL getInstance() { if (instance == null) { synchronized (SingletonDCL.class) { if (instance == null) { instance = new SingletonDCL(); } } } return instance; } }
该模式利用了静态内部类延迟初始化的特性,来达到与双重校验锁方式同样的功能。因为须要借助辅助类,并不经常使用。线程
public class SingletonInnerClass { /** * 私有构造方法 */ private SingletonInnerClass() { } /** * 惟一公开获取实例的方法(静态工厂方法) * * @return */ public static SingletonInnerClass getInstance() { return LazyHolder.INSTANCE; } /** * 私有静态内部类 */ private static class LazyHolder { private static final SingletonInnerClass INSTANCE = new SingletonInnerClass(); } }
该方式利用了枚举类的特性,不只能避免线程同步问题,还防止反序列化从新建立新的对象。这种方式是 Effective Java 做者 Josh Bloch 提倡的方式。
但因为这种编码方式还不能适应,因此实际工做中不多使用。
public enum SingletonEnum { INSTANCE; public void method() { System.out.println("枚举类中定义方法!"); } }