单例模式

Posted mr-hanexp

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式相关的知识,希望对你有一定的参考价值。

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

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

饿汉式

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

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

懒汉式

//懒汉式
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();
    }
}

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

枚举单例

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

安全

技术图片

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

以上是关于单例模式的主要内容,如果未能解决你的问题,请参考以下文章

常用代码片段

性能比较好的单例写法

片段作为 Android 中的单例

单例片段或保存网页视图状态

你熟悉的设计模式都有哪些?写出单例模式的实现代码

单例模式以及静态代码块