饿汉式
传统类加载方式
/**
* @author qingh.yxb
* @date 2018/12/26 10:38 饿汉式加载
*/
public class SingletonDemo {
/**
* jvm在类加载第二阶段链接过程中会有一个准备的动作,
* 这个动作会将instance初始化为null,
* 然后在加载的最后阶段-初始化阶段,真正实例化SingletonDemo,
* 整个过程保证唯一
*/
private static SingletonDemo instance = new SingletonDemo();
private SingletonDemo() {}
/**
* 获取单例
*
* @return
*/
public static SingletonDemo getInstance() {
return instance;
}
}
枚举方式
**
* @author qingh.yxb
* @date 2018/12/26 11:45
*
*/
public enum SingletonEnum {
/**
* 实例
*/
instance;
public void doSomething() {
System.out.println("singleton test " + instance.hashCode());
}
}
枚举方式目前是单例的最优解决方案,书写简洁,线程安全,可以防止反射创建新实例,可以有效避免当单例类实现序列化接口时,序列化引起的对单例的破坏(ObjectInputStream反序列化过程会通过反射调用无参数的构造方法创建一个新的对象,解决方式是构造readResolve方法;传统单例实现方式,如果内部聚合和了其他对象,需要transient使其无法序列化)。
唯一的不足是:枚举单例的加载不是懒加载,枚举类在编译后,是一个继承了java.lang.Enum的final class,内部维护的instance是static&final的(如下图),说明在类加载阶段必须赋值且不可更改。
具体实例化枚举实例是在静态代码块中完成的,如下图:
在初始化阶段会对static final SingletonEnum instance赋值。
懒汉式
DCL方式
/**
* @author qingh.yxb
* @date 2018/12/26 11:01 懒汉式--double check
*/
public class SingletonDemo2 {
private static SingletonDemo2 singletonDemo2;
private SingletonDemo2() {}
public static SingletonDemo2 getInstance() {
if (null == singletonDemo2) {
//多线程环境下,会出现多于一个线程进入到同步代码块内
synchronized (SingletonDemo2.class) {
//double check 保证唯一
if (null == singletonDemo2) {
singletonDemo2 = new SingletonDemo2();
}
}
}
return singletonDemo2;
}
}
内部类方式
内部类方式实现单例模式不会在装载所需单例类的时候进行实例的创建,而会推迟到获取实例时进行构造实例。例如:在调用doOtherthing时,并不会涉及到SingletonDemo3 的实例,因此不需要对SingletonDemo3 实例化,只需加载SingletonDemo3 便可;而在调用getInstance方法时目的性很明确,要获取一个SingletonDemo3 的实例,调用getInstance会去读取SingletonHolder 的静态变量instance,触发getstatic,即触发内部类加载,构造SingletonDemo3实例,具备了延迟加载的功能,并全局保证唯一,且效率高。
/**
* @author qingh.yxb
* @date 2018/12/26 11:14 懒汉式-内部类
*
*/
public class SingletonDemo3 {
private SingletonDemo3() {}
/**
* 持有实例的内部类
*/
private static class SingletonHolder {
private static SingletonDemo3 instance = new SingletonDemo3();
}
public static SingletonDemo3 getInstance() {
return SingletonHolder.instance;
}
/**
* 其他方法
*/
public static void doOtherthing(){
}
}
工厂方法模式
用工厂方法模式实现单例模式的功能
类图:
产品接口:
public interface Product {
void doSomething();
}
具体产品
public class ProductDemo1 implements Product{
public void doSomething() {
System.out.println("demo1");
}
}
public class ProductDemo2 implements Product {
public void doSomething() {
System.out.println("demo2");
}
}
单例工厂
import java.util.Map;
/**
* @author qingh.yxb
* @date 2018/12/26 16:21
*/
public class SingletonFactory {
private enum Type {
/**
* 产品一
*/
DEMO1("demo1"),
/**
* 产品二
*/
DEMO2("demo2");
/**
* 产品生产标识code
*/
private String code;
Type(String code) {
this.code = code;
}
}
/**
* 实例缓存
*/
private static Map<String, Product> cacheMap;
public static Product getInstance(String type) {
Product product = null;
if (cacheMap.containsKey(type)) {
product = cacheMap.get(type);
} else {
if (Type.DEMO1.code.equals(type)) {
product = new ProductDemo1();
} else {
product = new ProductDemo2();
}
cacheMap.put(type, product);
}
return product;
}
}
工厂方法模式实现单例,可以很容易的拓展到限制产品的最大实例化数量,即有上限的多例模式。