饿汉式:
/** * 单利模式:饿汉式加载 * 饿汉单例模式代码中,static变量会在类装载时初始化,此时也不会涉及多个线程对象访问对象的问题。虚拟机保证只会装载一次该类,肯定不会发生并发访问的问题。 * 因此,可以省略synchronized关键字 * 问题:如果只是加载本类,而不是要调用getInstance(),甚至永远没有调用,则会造成资源浪费。 * @author zw * */ public class HungryLoad { //类初始化时,立即加载这个对象(没有延时加载的优势)。加载类时,天然是线程安全的。 private static HungryLoad instance = new HungryLoad(); //私有化构造器。 private HungryLoad() { } //方法没有同步,调用效率高。 public static HungryLoad getInstance(){ return instance; } }懒汉式
/** * 单例模式:懒汉式加载 * 延迟加载,懒加载!真正用的时候才加载。 * 问题:资源利用率高了。但是每次调用getInstance()方法都要同步,并发效率较低。 * @author zw * */ public class LazyLoad { //类初始化时,不初始化这个对象(延时加载,真正用的时候再创建) private static LazyLoad instance; //私有化构造器 private LazyLoad() { //防止通过反射创建多个对象 if (instance != null) { throw new RuntimeException(); } } //方法同步,调用效率低。 public static synchronized LazyLoad getInstance(){ if (instance == null) { instance = new LazyLoad(); } return instance; } }静态内部类
/** * 单例模式:静态内部类(也是一种懒加载) * 外部类没有static属性,则不会像饿汉式那样立即加载对象。 * 只有真正调用getInstance(),才会加载静态内部类,加载类时是线程安全的。instance是static final 类型,保证了内存中只有这样一个实例存在, * 而且只能被赋值一次,从而保证了线程安全性。 * 兼备了并发高效调用和延迟加载的优势! * @author zw * */ public class StaticInnerclassLoad { private static class InnerClass{ private static final StaticInnerclassLoad instance = new StaticInnerclassLoad(); } private StaticInnerclassLoad() { } public static StaticInnerclassLoad getInstance() { return InnerClass.instance; } }枚举
/** * 单例模式:枚举加载 * 实现简单 * 枚举本身就是单例模式,由JVM从根本上提供保障!避免通过反射和反序列化的漏洞! * 问题:无延迟加载。 * @author zw * */ public enum EnumLoad { /** * 定义一个枚举元素,它就代表了Singleton的一个实例 */ INSTANCE; /** * 单例可以有自己的操作 * @return */ public void singletonOperation(){ //功能处理 System.out.println("枚举加载的功能"); } }开发时,如果类创建对象的代价很高,就用延时加载(懒汉式);类调用效率非常频繁,用饿汉式
单例对象:占用 资源少;不需要延时加载。 枚举式 好于 饿汉式 单例对象:占用 资源大;需要延时加载。 静态内部类式 好于 懒汉式防止通过反射创建多个对象,在构造方法中加 if (instance != null) { throw new RuntimeException(); }
单例模式应用的场景一般发现在以下条件下:
(1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
(2)控制资源的情况下,方便资源之间的互相通信。如线程池等。
