大话单例模式

标题概念

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

单例模式基本实现

懒汉模式

这是最基本的单例模式,实现了懒加载,但是多线程不安全,没有添加锁synchronized,严格意义上来说这不算是单例模式。

实现方式

public class Singleton {
        private static Singleton instance;

        private Singleton() {}

        public static Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
}

饿汉式

线程安全,比较常用,但容易产生垃圾,因为一开始就初始化

实现方式

public class Singleton {
        private static Singleton instance = new Singleton();

        private Singleton() {}

        public static Singleton getInstance() {
            return instance;
        }
    }

以上两种基本实现方式都有其缺点,那么我们来改造下吧,别说了 看代码

讲解

public class Singleton {
    private static Singleton instance;

    private Singleton() {
        System.out.println("创建单例模式");
    }

    public static Singleton getInstance() {
        if (instance == null) {
        	if (instance == null) {
                 instance = new Singleton();
             }
        }
        return instance;
    }
}

public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            new Thread() {
                @Override
                public void run() {
                    super.run();
                    Singleton.getInstance();
                }
            }.start();
        }
    }

我们期望的结果应该是

创建单例模式

而实际结果是

创建单例模式
创建单例模式
创建单例模式
创建单例模式
创建单例模式

没错就是这样,不要问为什么,这就是多线程的秒处啦

我们都知道无论是什么语言 java、c、go、dart、.net等最终都会转化成在CUP执行的一条条指令,如果当前进程下多个线程在执行任务,cpu会快速切换线程。例子中有5个线程(A,B,C,D,E)同时开启,线程A执行到判断语句if(instance == null) 时,同时快速切换至B或者C或者D或者E,他们的判断条件都成立(instance此时还为空),再次进行多次切换,(线程A、线程B、线程C、线程D、线程E)都进行赋值操作,所以就创建了5个对象

如何解决呢,请看下面

改造

懒汉式加锁

public class Singleton {
	private static volatile Singleton instance;

	private Singleton() {}

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

内部静态类模式

当 Singleton 类加载时,静态内部类 SingletonHolder 没有被加载进内存。只有当调用 getUniqueInstance() 方法从而触发SingletonHolder.INSTANCE 时 SingletonHolder才会被加载,此时初始化 INSTANCE 实例。
这种方式不仅具有延迟初始化的好处,而且由虚拟机提供了对线程安全的支持。

public class Singleton {

    private static class Instance {
        private static Singleton instance = new Singleton();
    }

    private Singleton() {
        System.out.println("创建单例模式");
    }

    public static Singleton getInstance() {
        return Instance.instance;
    }
}

枚举模式

这是单例模式的最佳实践,它实现简单,并且在面对复杂的序列化或者反射×××的时候,能够防止实例化多次。

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

总结

单例模式推荐使用静态内部类和枚举模式,在Android开发中我个人推荐使用静态内部类模式。
单例模式如何暴力破解和防护呢?

点赞