对于单例模式,我想大家并不陌生,因为它是我们代码编写中比较常用的设计模式之一。
不过,大家可能不知道的是,单例模式还有很多别样的编写方式。
首先,先给大家说一下单例模式的几要素:
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;
}
}
网友评论