标签:lang targe 分布 额外 method 阻塞 print 2.4.1 been
1 饿汉模式
1.1本质: 在类加载的时候就创建实例,需要获取实例时直接返回已创建的实例
1.2 优点:线程安全
1.3 缺点: 类加载的时候就创建实例,浪费空间
1.4 代码示例:
package com.blueStarWei.pattern; public class HungrySingleton { //create instance when loading class private static HungrySingleton singleton = new HungrySingleton(); public static HungrySingleton getInstance(){ return singleton; } }
【为了减省空间的浪费,因此人们想到了在需要获取实例的时候创建实例,因此产生了懒汉模式】
2. 懒汉模式
2.1 本质: 当需要获取实例的时候,先进行判断,如果实例不存在,就创建实例,否则直接返回已存在的实例【避免了在加载类的同时直接创建实例】
2.2 懒汉模式1.0版本
package com.blueStarWei.pattern; public class LazySingleton { private static LazySingleton singleton; public static LazySingleton getInstance(){ if(singleton == null){ singleton = new LazySingleton(); } return singleton; } }
2.2.1 优点:节省了空间
2.2.2 缺点: 线程不安全【如果多个线程同时执行if判断,因为多个线程获取的singleton1都是空,所以会创建多个实例】
【为了避免懒汉模式的线程不安全问题,人们想到了对getInstance()添加synchronized修饰符,于是产生了懒汉模式1.1版本】
2.3 懒汉模式1.1版本
package com.blueStarWei.pattern; public class LazySingleton1 { private static LazySingleton1 singleton; public static synchronized LazySingleton1 getInstance(){ if(singleton == null){ singleton = new LazySingleton1(); } return singleton; } }
2.3.1 优点: 节省空间、线程安全
2.3.2 缺点: 性能不好【synchronized会造成线程阻塞】
【为了避免线程阻塞的出现,人们又想到了双重校验锁,因此产生了懒汉模式1.2版本】
2.4 懒汉模式1.2版本
package com.blueStarWei.pattern; public class LazySingleton2 { private static LazySingleton2 singleton; public static LazySingleton2 getInstance(){ if(singleton == null){ synchronized (LazySingleton1.class) { if(singleton == null){ singleton = new LazySingleton2(); } } } return singleton; } }
2.4.1 优点: 节省空间,线程安全,性能相对有优化【只是优化了已经存在实例的情况,即:当实例已经被创建,再调用getInstance()的时候就不会经过synchronized修饰符】
2.4.2 缺点:使用了synchronized修饰符,线程仍然会有阻塞情况的发生。
【为了避免使用synchronized修饰符,人们想到了静态内部类(因为一个类被加载,当且仅当该类的某个静态成员被调用),于是懒汉模式2.0时代到来】
2.5 懒汉模式2.0版本【推荐版本】
package com.blueStarWei.pattern; /** * 因为对象实例化是在内部类加载时构建,因此是线程安全的【毕竟类只加载一次嘛】 * @author HuWei * */ public class LazySingleton3 { //当getInstance()方法第一次被调用时,内部类被加载 static class SingletonHolder { private static final LazySingleton3 singleton3 = new LazySingleton3(); } //没有使用synchronized修饰符,避免了性能损耗 public static LazySingleton3 getInstance() { return SingletonHolder.singleton3; } }
2.5.1 优点: 节省空间、线程安全、避免性能的额外损耗
2.5.2 缺点: 在反射作用下,单例模式会被破坏
【为了防止反射破坏单例模式,所以产生了单例模式3.0版本】
2.6 单例模式3.0版本
2.6.1 版本代码
package com.blueStarWei.pattern; public class LazySingleton4 { /* -------添加部分 start-------- * 作用:第二次调用构造函数(即:创建第二个实例)时抛出异常 * */ private static boolean initialized = false; public LazySingleton4() { synchronized (LazySingleton4.class) { if(initialized == false){ initialized = !initialized; }else{ throw new RuntimeException("Singleton has been broken!"); } } } /* -------添加部分 end-------- */ //当getInstance()方法第一次被调用时,内部类被加载 static class SingletonHolder { private static final LazySingleton4 singleton4 = new LazySingleton4(); } //没有使用synchronized修饰符,避免了性能损耗 public static LazySingleton4 getInstance() { return SingletonHolder.singleton4; } }
2.6.1.1 版本Demo
package com.blueStarWei.pattern; import java.lang.reflect.Constructor; /** * 通过反射调用时会报错 * Caused by: java.lang.RuntimeException: Singleton has been broken! * @author HuWei * */ public class LazySingleton4Demo { public static void main(String[] args) { //通过getInstance()创建实例 LazySingleton4 sington = LazySingleton4.getInstance(); //通过反射创建实例 LazySingleton4 sington4 = null; try { Class<LazySingleton4> clazz = LazySingleton4.class; Constructor<LazySingleton4> constructor = clazz.getDeclaredConstructor(); sington4 = constructor.newInstance(); } catch (Exception e) { e.printStackTrace(); } System.out.println("getInstance() : "+sington); System.out.println("invoke : "+sington4); } }
2.6.1.2 Demo日志
java.lang.reflect.InvocationTargetException at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) at java.lang.reflect.Constructor.newInstance(Unknown Source) at com.blueStarWei.pattern.LazySingleton4Demo.main(LazySingleton4Demo.java:21) Caused by: java.lang.RuntimeException: Singleton has been broken! at com.blueStarWei.pattern.LazySingleton4.<init>(LazySingleton4.java:19) ... 5 more getInstance() : com.blueStarWei.pattern.LazySingleton4@7852e922 getInstance() : com.blueStarWei.pattern.LazySingleton4@7852e922 invoke : null
2.6.2 反射破环单例模式示例
package com.blueStarWei.pattern; import java.lang.reflect.Constructor; /** * 不难发现,通过getInstance()和反射创建的实例的内存地址不一样,即不是同一个实例对象 * @author HuWei * */ public class LazySingleton3Demo { public static void main(String[] args) { //通过getInstance()创建实例 LazySingleton3 sington = LazySingleton3.getInstance(); LazySingleton3 sington2 = LazySingleton3.getInstance(); //通过反射创建实例 LazySingleton3 sington3 = null; try { Class<LazySingleton3> clazz = LazySingleton3.class; Constructor<LazySingleton3> constructor = clazz.getDeclaredConstructor(); sington3 = constructor.newInstance(); } catch (Exception e) { e.printStackTrace(); } System.out.println("getInstance() : "+sington); //getInstance() : com.blueStarWei.pattern.LazySingleton3@15db9742 System.out.println("getInstance() : "+sington2); //getInstance() : com.blueStarWei.pattern.LazySingleton3@15db9742 System.out.println("invoke : "+sington3); //invoke : com.blueStarWei.pattern.LazySingleton3@6d06d69c } }
【在分布式系统中,单例类有时需要实现Serializable接口。以上版本通过序列和反序列化产生的实例将会不是同个实例对象,所以产生了懒汉模式4.0版本】
2.7 懒汉模式4.0版本
2.7.1 Demo代码
package com.blueStarWei.pattern; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; public class LazySingleton4Demo2 { public static void main(String[] args) { LazySingleton4 singleton = LazySingleton4.getInstance(); try { ObjectOutput out = new ObjectOutputStream(new FileOutputStream("fileName.txt")); out.writeObject(singleton); out.close(); //deserializable from file to object ObjectInput in = new ObjectInputStream(new FileInputStream("fileName.txt")); LazySingleton4 singleton2 = (LazySingleton4)in.readObject(); in.close(); System.out.println("Serializable : "+singleton); System.out.println("Deserializable : "+singleton2); } catch (Exception e) { e.printStackTrace(); } } }
2.7.2 反序列返回不同的对象示例
public class LazySingleton4 implements Serializable
2.7.2.1 Demo日志
Serializable : com.blueStarWei.pattern.LazySingleton4@33909752
Deserializable : com.blueStarWei.pattern.LazySingleton4@776ec8df
2.7.3 版本代码
package com.blueStarWei.pattern; import java.io.Serializable; public class LazySingleton4 implements Serializable{ private static final long serialVersionUID = 1L; private static boolean initialized = false; public LazySingleton4() { synchronized (LazySingleton4.class) { if(initialized == false){ initialized = !initialized; }else{ throw new RuntimeException("Singleton has been broken!"); } } } static class SingletonHolder { private static final LazySingleton4 singleton4 = new LazySingleton4(); } public static LazySingleton4 getInstance() { return SingletonHolder.singleton4; } /* ----添加部分 start---- */ /** * 反序列化的结果仍然通过getInstance()获取 */ private Object readResolve(){ return getInstance(); } /* ----添加部分 end---- */ }
2.7.3.1 Demo日志
Serializable : com.blueStarWei.pattern.LazySingleton4@33909752
Deserializable : com.blueStarWei.pattern.LazySingleton4@33909752
3 总结
实际项目中,一般从懒汉模式2.0、3.0、4.0版本中选择一种即可
更多内容,请访问:http://www.cnblogs.com/BlueStarWei/
标签:lang targe 分布 额外 method 阻塞 print 2.4.1 been
原文地址:https://www.cnblogs.com/BlueStarWei/p/8997932.html