对于单例模式,我想大家并不陌生,因为它是我们代码编写中比较常用的设计模式之一。
不过,大家可能不知道的是,单例模式还有很多别样的编写方式。
首先,先给大家说一下单例模式的几要素:
1.定义一个自己私有的对象;
2.定义一个私有的构造函数,使得外接不可以直接拿到对象本身;
3.定义一个公共的静态方法,用于返回私有对象;
4.只有在私有对象为空的时候才去new一次对象;
然后,给大家分享下三种类型的单例模式:懒汉式,饿汉式以及登记式,这三种模式是对私有对象创建模式的一种分类。
1.懒汉式
所谓懒汉式,就是在需要创建对象的时候才进行创建。
(1)普通懒汉式
public class Singleton {
? private static?Singleton instance;
? private?Singleton () {}
? public static?Singleton getInstance() {
? ? ? if (instance == null) {
? ? ? ? ? ?instance = new?Singleton();
? ? ? ?}
? ? ? ?return instance;
? ? }
}
缺点:存在线程不安全性。在多线程环境下,如果多个线程同时实例化某懒汉式的单例类,那么就有可能在单例类内部多次初始化实例,造成单例模式失效。因此,对于多线程程序中的懒汉式单例,还需要对其加锁,确保线程安全。
(2)线程安全的懒汉式
a.无关对象锁
public class Singleton {
? private static?Singleton instance;
? private?static?Object syncLock?= new Object();
? private?Singleton () {}
? public static?Singleton getInstance() {
? ? synchronize(syncLock) {
? ? ? ? ?if (instance == null) {
? ? ? ? ? ? ? instance = new?Singleton();
? ? ? ? ? ?}
? ? ? ? ? return instance;
? ? ? ? }
? ? }
}
b.当前对象锁
public class Singleton {
? private static?Singleton instance;
? private?Singleton () {}
? public static?Singleton getInstance() {
? ? synchronize(this) {
? ? ? ? ?if (instance == null) {
? ? ? ? ? ? ? instance = new?Singleton();
? ? ? ? ? ?}
? ? ? ? ? return instance;
? ? ? ?}
? ? }
}
c.类本身锁
public class Singleton {
? private static?Singleton instance;
? private?Singleton () {}
? public static?Singleton getInstance() {
? ? ?if (instance == null) {
? ? ? ? synchronize(Singleton.class) {
? ? ? ? ? ? ?if (instance == null) {
? ? ? ? ? ? ? ? ? instance = new?Singleton();
? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? return instance;
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
说明:如上写了a b c三种线程锁的方式,目的在于告诉大家,b方式的线程锁在单例模式中是不可取的,原因是getInstance方法是一个静态方法,在它的内部不能使用未静态的或者未实例化的类对象(避免空指针异常);
缺点:线程安全的懒汉式单例执行效率不如饿汉式
(3)内部类形式的懒汉式
public class Singleton {
? private?Singleton () {}
? public static?Singleton getInstance() {
? ? ? ?return Holder.SINGLETON?;
? ? }
? ? private static class Holder {
? ? ? ? private?static?final?Singleton SINGLETON =?new?Singleton();
? ? }
}
说明:这种方式解决了上述的两种缺点,并优于饿汉式的空间换时间方案。
2.饿汉式
所谓饿汉式,就是类一编译及创建好私有对象。
public class Singleton {
? private static?Singleton instance = new Singleton();
? private?Singleton () {}
? public static?Singleton getInstance() {
? ? ? ?return instance;
? ? }
}
缺点:类一编译即占用一定的内存存储对象,不过效率优于线程安全的懒汉式单例。典型的空间换时间方案。
3.登记式
所谓登记式,就是将私有对象存放在特定的堆栈中,用于单例对象的分组,目前我还没发现使用的环境是啥,欢迎提出指导意见。
//采用Map配置多个单例??
public?class Singleton {??
????//?设立静态变量,直接创建实例??
????private?static?Map?map?=?new?HashMap();??
????//?-----受保护的-----构造函数,不能是私有的,但是这样子类可以直接访问构造方法了??
????//解决方式是把你的单例类放到一个外在的包中,以便在其它包中的类(包括缺省的包)无法实例化一个单例类。??
????protected Singleton()?{??
????????System.out.println("-->私有化构造函数被调用,创建实例中");??
????}??
????//?开放一个公有方法,判断是否已经存在实例,有返回,没有新建一个在返回??
????public?static Singleton getInstance(String?name)?{??
????????if?(name?==?null)?{??
????????????name?= Singleton.class.getName();??
????????????System.out.println("-->name不存在,name赋值等于"+MySingleton3.class.getName());??
????????}??
????????if?(map.get(name)?==?null)?{??
????????????try?{??
????????????????System.out.println("-->name对应的值不存在,开始创建");??
????????????????map.put(name,?(MySingleton3)Class.forName(name).newInstance());??
????????????}?catch?(InstantiationException?e)?{??
????????????????e.printStackTrace();??
????????????}?catch?(IllegalAccessException?e)?{??
????????????????e.printStackTrace();??
????????????}?catch?(ClassNotFoundException?e)?{??
????????????????e.printStackTrace();??
????????????}??
????????} else?{??
????????????System.out.println("-->name对应的值存在");??
????????}??
????????System.out.println("-->返回name对应的值");??
????????return?map.get(name);??
????}??
????public?Map?getMap() {??
????????return?map;??
? ? }
}