单例模式

  • 1、单例类只能有一个实例。
  • 2、单例类必须自己创建自己的唯一实例。
  • 3、单例类必须给所有其他对象提供这一实例。

总之就是构造器私有化,提供一个公共的方法创建实例供外部使用。

饿汉式

第一种

//饿汉式单例
public class Hungry {
    //可能会造成空间的浪费,因为一开始就将这个对象new出来了
    private Hungry(){

    }
    private final static Hungry HUNGRY = new Hungry();
    public static Hungry getInstance(){
        return HUNGRY;
    }
}

第二种:静态代码块

class Hungry01 {
    private Hungry01() {

    }
    private static Hungry01 hungry01;
    //通过静态代码块进行对象实例的创建
    static {
        hungry01 = new Hungry01();
    }
    public static Hungry01 getInstance() {
        return hungry01;
    }
}

懒汉式

//懒汉式
public class Lazy {
    private Lazy() {
        
    }
    private static Lazy lazy;

    public static Lazy getInstance() {
        if (lazy == null) {
            lazy = new Lazy();
        }
        return lazy;
    }

问题:多线程下会出问题

public static void main(String[] args) {
    for (int i = 0; i < 20; i++) {
        new Thread(() -> {
            Lazy.getInstance();
        }
        ).start();
    }
}
/**
多线程下执行创建了多个实例
 -----------------------
 Thread-0 Ok
 Thread-1 Ok
 -----------------------
 */

DCL懒汉式

//DCL双重检测锁
public class DCL {
    private DCL(){

    }
    /*加上volatile禁止指令重排,因为下面dcl = new DCL()这个动作不是原子性的,
      分为三步:1.分配内存空间。2.执行构造方法初始化对象。3.将这个对象指向这个内存空间。
      2和3的执行顺序可能被交换,多线程就有可能造成空指针的异常。
    *
    */
    private volatile static DCL dcl;
    public static DCL getInstance(){
        //通过双重检测
        if(dcl== null){
            //需要锁这个类
            synchronized (DCL.class){
                if (dcl == null){
                    dcl = new DCL();
                }
            }
        }
        return dcl;
    }

多线程下安全,但是能被反射破坏。

静态内部类单例

//静态内部类内部类单例
public class Inner {
    private Inner(){}
    
	public static Inner getInstance(){
  	  return InnerClass.INNER;
	}
	
	public static class InnerClass{
   	 private final static Inner INNER = new Inner();
    }
}

InnerClass在Inner类加载的时候并不会立即进行实例化,而是在调用了InnerClass.INNER的时候才进行实例化,所以保证了延迟加载(懒),效率高。

以上方式创建的单例都能够被反射破坏

枚举单例

//枚举单例
public enum  ESingle{
    INSTANCE;
    public ESingle getInstance(){
        return INSTANCE;
    }
}

安全

因为不能通过反射来进行实例化。

posted @ 2020-05-30 15:03  MrHanhan  阅读(115)  评论(0编辑  收藏  举报