单例模式
本文链接:https://blog.csdn.net/weixin_42152604/article/details/87915944
单例的创建方式:
1、饿汉式:类初始化的时候,会立即加载该对象,线程天生安全,调用效率高。
2、懒汉式:类初始化时,不会初始化该对象,真正需要使用的时候才会去创建该对象,具备懒加载功能。
3、静态内部类方式:结合了懒汉式和饿汉式各自的优点,真正需要对象的时候才会加载,加载类是线程安全的。
4、枚举单例:使用枚举实现单例模式,实现简单、调用效率高,枚举本身就是单例,由JVM从根本上提供保障,避免通过反射和反序列化的漏洞,缺点是没有延迟加载。
5、双重检测方式(因为JVM本身重排序的原因,可能会出现多次的初始化)
示例:
1、饿汉式
//饿汉式 public class SingletonDemo01 { // 类初始化时,会立即加载该对象,线程天生安全,调用效率高 private static SingletonDemo01 singletonDemo01 = new SingletonDemo01(); private SingletonDemo01() { System.out.println("SingletonDemo01初始化"); } public static SingletonDemo01 getInstance() { System.out.println("getInstance"); return singletonDemo01; } public static void main(String[] args) { SingletonDemo01 s1 = SingletonDemo01.getInstance(); SingletonDemo01 s2 = SingletonDemo01.getInstance(); System.out.println(s1 == s2); } }
2、懒汉式
//懒汉式 public class SingletonDemo02 { //类初始化时,不会初始化该对象,真正需要使用的时候才会创建该对象。 private static SingletonDemo02 singletonDemo02; private SingletonDemo02() { } public synchronized static SingletonDemo02 getInstance() { if (singletonDemo02 == null) { singletonDemo02 = new SingletonDemo02(); } return singletonDemo02; } public static void main(String[] args) { SingletonDemo02 s1 = SingletonDemo02.getInstance(); SingletonDemo02 s2 = SingletonDemo02.getInstance(); System.out.println(s1 == s2); } }
3、静态内部类
public class SingletonDemo03 { private SingletonDemo03() { System.out.println("初始化.."); } public static class SingletonClassInstance { private static final SingletonDemo03 singletonDemo03 = new SingletonDemo03(); } // 方法没有同步 public static SingletonDemo03 getInstance() { System.out.println("getInstance"); return SingletonClassInstance.singletonDemo03; } public static void main(String[] args) { SingletonDemo03 s1 = SingletonDemo03.getInstance(); SingletonDemo03 s2 = SingletonDemo03.getInstance(); System.out.println(s1 == s2); } }
优势:兼顾了懒汉模式的内存优化(使用时才初始化)以及饿汉模式的安全性(不会被反射入侵)。
劣势:需要两个类去做到这一点,虽然不会创建静态内部类的对象,但是其 Class 对象还是会被创建,而且是属于永久带的对象。
4、枚举
public class User { public static User getInstance() { return SingletonDemo04.INSTANCE.getInstance(); } private static enum SingletonDemo04 { INSTANCE; // 枚举元素为单例 private User user; private SingletonDemo04() { .out.println("SingletonDemo04"); user = new User(); } public User getInstance() { return user; } } public static void main(String[] args) { User u1 = User.getInstance(); User u2 = User.getInstance(); System.out.println(u1 == u2); } }
5、双重检测锁
public class SingletonDemo04 { private SingletonDemo04 singletonDemo04; private SingletonDemo04() { } public SingletonDemo04 getInstance() { if (singletonDemo04 == null) { synchronized (this) { if (singletonDemo04 == null) { singletonDemo04 = new SingletonDemo04(); } } } return singletonDemo04; } }
单例防止反射攻击
在构造函数中,只能允许初始化一次即可
private static boolean flag = false; private SingletonDemo04() { if (flag == false) { flag = !flag; } else { throw new RuntimeException("单例模式被侵犯!"); } }
————————————————
版权声明:本文为CSDN博主「程序猿-南巷清风」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42152604/article/details/87915944