单例模式

单例模式是一种创建型模式,保证一个类只有一个实例对象。

场景:打印机,一个系统可存在多个打印任务,但只能有一个正在工作的任务;

          在Spring中创建的Bean实例默认都是单例模式存在的

懒汉式:在类加载时不初始化

1、懒汉式1,线程不安全

public class SingletonDemo1 {
    private static SingletonDemo1 instance;
    private SingletonDemo1(){}
    public static SingletonDemo1 getInstance(){
        if (instance == null) {
            instance = new SingletonDemo1();
        }
        return instance;
    }
}

2、懒汉式2、线程安全、引入锁效率低

public class SingletonDemo2 {
    private static SingletonDemo2 instance;
    private SingletonDemo2(){}
    public static synchronized SingletonDemo2 getInstance(){
        if (instance == null) {
            instance = new SingletonDemo2();
        }
        return instance;
    }
}

3、懒汉式、线程安全、效率高

  • 私有静态变量要用volatile修饰(volatile在这里其实是有两个作用:禁止指令重排序 和 保证数据可见性
  • 无参构造函数私有化(通过new的方式无法创建,只能通过getInstance方法来获取对象)
  • 双重检测下synchronized锁的是类而非成员变量
public class SingletonDemo3 {
    private volatile static SingletonDemo3 singletonDemo3;
    private SingletonDemo3(){}
    public static SingletonDemo3 getSingletonDemo3(){
        if (singletonDemo3 == null) {
            synchronized (SingletonDemo3.class) {
                if (singletonDemo3 == null) {
                    singletonDemo3 = new SingletonDemo3();
                }
            }
        }
        return singletonDemo3;
    }
}

饿汉式:在类加载时就完成了初始化,所以类加载比较慢,但获取对象的速度快。

4、饿汉式(需了解类的加载机制

public class SingletonDemo4 {
    private static SingletonDemo4 instance = new SingletonDemo4();
    private SingletonDemo4(){}
    public static SingletonDemo4 getInstance(){
        return instance;
    }
}

5、静态内部类

public class SingletonDemo5 {
    private static class SingletonHolder{
        private static final SingletonDemo5 instance = new SingletonDemo5();
    }
    private SingletonDemo5(){}
    public static final SingletonDemo5 getInsatance(){
        return SingletonHolder.instance;
    }
}

在加载外部类的时候,并不会同时加载其静态内部类,只有在发生调用的时候才会进行加载,加载的时候就会创建单例实例并返回,有效实现了懒加载

类级内部类结合多线程默认同步锁,同时实现延迟加载和线程安全。

单例模式可以被破坏吗?可以,通过反射或序列化

创建对象有几种方式?

1、通过new关键字对象

2、反射:通过class类的newInstance方法、通过Constructor类的newInstance方法

3、使用clone方法,类需要实现cloneable接口,并实现clone方法

4、反序列化,类需要实现Serializable接口

6、枚举

 

public enum Singleton{
   INSTANCE;
   public void doSomething(){
  }
}

 

1、枚举类隐式继承抽象类Enum,Enum并没有无参的构造方法,而且反射newInstance时判断类型是不是枚举,如果是则抛出异常,故不能通过反射创建枚举对象;
2、枚举序列化时仅将对象的name属性输出到结果中,反序列化通过枚举的valueOf()方法根据名字找到枚举对象,通过序列化获取的对象是一个;

 

注:FelEngine创建对象比较耗时,选择使用懒汉式单例模式,避免重复创建对象提高效率。

posted @ 2018-08-30 14:52  提拉米苏007  阅读(144)  评论(0编辑  收藏  举报