单例模式
1、饿汉式
1 /** 2 * 饿汉式:类一加载就创建,迫不及待的样子就是饿汉了 3 * 优点:天生的线程安全 4 * 缺点:饿汉式类多了就会影响项目启动效率 5 */ 6 public class SingleInstance01 { 7 /** 8 * 私有化构造函数,给出指定方法获取;因是静态属性,类加载时只会创建一次 9 * 所以线程安全 10 */ 11 private static SingleInstance01 singleInstance01 = new SingleInstance01(); 12 13 private SingleInstance01() { 14 } 15 16 private SingleInstance01 getInstance() { 17 return singleInstance01; 18 } 19 }
2、懒汉式
1 /** 2 * 懒汉式:就是要用的时候才创建,不用的时候不创建;懒汉式会出现线程不安全的情况 3 * 4 */ 5 public class SingleInstance02 { 6 private static SingleInstance02 instance02; 7 8 /** 9 * 记住:单例都要私有化构造函数的;不要问为什么,自己想想哦 10 */ 11 private SingleInstance02() {} 12 13 /** 14 * 给出获取单例的方法 15 */ 16 public static SingleInstance02 getInstance(){ 17 /** 18 * 为什么不安全?因为多线程的时候该方法同时被调用时, 19 * 该对像会创建多次,成为不同的对像的 20 */ 21 if(instance02 == null){ 22 instance02=new SingleInstance02(); 23 } 24 return instance02; 25 } 26 }
3、懒汉式(线程安全)
1 /** 2 * 懒汉式(保证线程安全):就是要用的时候才创建,不用的时候不创建; 3 * 4 */ 5 public class SingleInstance03 { 6 private static SingleInstance03 instance03; 7 8 /** 9 * 记住:单例都要私有化构造函数的;不要问为什么,自己想想哦 10 */ 11 private SingleInstance03() {} 12 13 /** 14 * 给出获取单例的方法 15 * 同步获取对像的方法,则可保证线程安全了 16 * 缺点:多线程调用时,就会造成执行排队,影响性能 17 */ 18 public synchronized static SingleInstance03 getInstance(){ 19 if(instance03 == null){ 20 instance03=new SingleInstance03(); 21 } 22 return instance03; 23 } 24 }
4、双重校验锁
1 /** 2 * 双重校验锁:线程安全 3 * 缺点:第一次进行创建的时候效率会比较低 4 */ 5 public class SingleInstance04 { 6 private volatile static SingleInstance04 instance04; 7 /** 8 * 记住:单例都要私有化构造函数的;不要问为什么,自己想想哦 9 */ 10 private SingleInstance04() {} 11 12 public static SingleInstance04 getInstance(){ 13 if (instance04 == null){//第一次判断是空开启锁 14 synchronized (SingleInstance04.class){ 15 if(instance04 == null){//第二次判断空开始创建对像 为什么第2次还要判断空?考虑多线程,具体原因不述 16 instance04=new SingleInstance04(); 17 } 18 } 19 } 20 return instance04; 21 } 22 }
5、静态内部模式
public class SingletonV5 { private SingletonV5() { System.out.println("对象初始..."); } public static SingletonV5 getInstance() { return SingletonV5Utils.singletonV5; } /** * 静态内部方式能够避免同步带来的效率问题和有能实现延迟加载
* 继承了懒汉式的优点,同时解决双重校验锁的第一次加载慢的的问题 */ public static class SingletonV5Utils { private static SingletonV5 singletonV5 = new SingletonV5(); } public static void main(String[] args) { System.out.println("项目启动成功"); SingletonV5 instance1 = SingletonV5.getInstance(); SingletonV5 instance2 = SingletonV5.getInstance(); System.out.println(instance1 == instance2); } }
6、枚举式
public enum EnumSingleton { INSTANCE; // 枚举能够绝对有效的防止实例化多次,和防止反射和序列化破解 public void add() { System.out.println("add方法..."); } } public static void main(String[] args) throws Exception { EnumSingleton instance1 = EnumSingleton.INSTANCE; EnumSingleton instance2 = EnumSingleton.INSTANCE; System.out.println(instance1 == instance2); Constructor<EnumSingleton> declaredConstructor = EnumSingleton.class.getDeclaredConstructor(); declaredConstructor.setAccessible(true); EnumSingleton v3 = declaredConstructor.newInstance(); System.out.println(v3==instance1); }
通过反射和序列化技术破坏单例
// 1.反射破坏单例: 使用懒汉式创建对象
SingletonV3 instance1 = SingletonV3.getInstance();
// 2. 使用Java反射技术初始化对象 执行无参构造函数
Constructor<SingletonV3>
declaredConstructor = SingletonV3.class.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
SingletonV3 instance2 = declaredConstructor.newInstance();
System.out.println(instance1 == instance2);
-------------------------------------------
//可以通过私有化构造数函数防止
private SingletonV3() throws Exception {
synchronized (SingletonV3.class) {
if (singletonV3 != null) {
throw new Exception("该对象已经初始化..");
}
System.out.println("执行SingletonV3无参构造函数...");
}
}
--------------------------------
//使用序列化破坏单例
Singleton instance = Singleton.getInstance(); FileOutputStream fos = new FileOutputStream("E:\\code\\Singleton.obj"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(instance); oos.flush(); oos.close(); FileInputStream fis = new FileInputStream("E:\\code\\Singleton.obj"); ObjectInputStream ois = new ObjectInputStream(fis); Singleton singleton2 = (Singleton) ois.readObject(); System.out.println(singleton2==instance)
浙公网安备 33010602011771号