设计模式之单例模式(Java)

来源:互联网 发布:程序员修改bug搞笑图 编辑:程序博客网 时间:2024/06/06 18:34

设计模式之单例模式(Java)

  • 设计模式之单例模式Java
    • 概念
    • 特点
    • 实现
    • 问题与总结


概念

    Java单例模式是一种常见的设计模式,其主要作用是保证在Java程序中,某个类只有一个实例(对象)存在,某些管理      器和控制器常被设计成单例模式。

特点

    1. 单例类只能有一个实例。    2. 单例类的实例必须由该单例类自行创建。    3. 单例类必须为所有其他对象提供这一实例。

实现

    1. 懒汉式(非线程安全)        public class Singleton1 {            private Singleton1() {}            private static Singleton1 instance = null;            public static Singleton1 getInstance() {                if (instance == null) {                    instance = new Singleton1();                }                return instance;            }        }        Singleton1类通过将构造方法修饰符限制为private,防止被其他外部类实例化,它的唯一实例只能通过          getInstance()方法获得(通过Java反射机制可以访问类的私有方法并实例化,此处暂不讨论)。该单例模          式为懒汉式单例,并没有考虑到并发环境下的线程安全问题,故并发环境下有可能出现多个实例。    2. 懒汉式(线程安全)            public class Singleton2 {            private static Singleton2 instance;            private Singleton2() {}            public static synchronized Singleton2 getInstance() {            if (instance == null) {                instance = new Singleton2();            }            return instance;        }        }        这种实现方式能够在并发环境中线程安全,并且实现了懒加载。但是效率很低,大多数情况下是不需要同步的。    3. 饿汉式            public class Singleton3 {            private static Singleton3 instance = new Singleton3();            private Singleton3() {}            public static Singleton3 getInstance() {                return instance;            }        }        这种基于类加载机制能够保证在并发环境中线程安全,没有实现懒加载。但是,该实例在类加载过程中就实例          化,而大多数情况下都是调用getInstance()方法之后才使用该实例,并不需要在类加载时初始化该实例。    4. 饿汉式-变种           public class Singleton4 {            private static Singleton4 instance = null;            static {                instance = new Singleton4();            }            private Singleton4() {}            public static Singleton4 getInstance() {                return instance;            }        }        这种实现方式会在第一次类加载时初始化实例,与方法3一般无二。    5. 懒汉式-双重校验锁           public class Singleton5 {            private volatile static Singleton5 singleton;            private Singleton5() {}            public static Singleton5 getSingleton() {                if (singleton == null) {                    synchronized (Singleton5.class) {                        if (singleton == null) {                            singleton = new Singleton5();                        }                    }                }                return singleton;            }        }        这是第2中实现方式的升级,这种实现方式基本可以解决线程安全,但是有个别情况无法保证线程安全(此处暂          不讨论)。    6. 懒汉式-静态内部类           public class Singleton6 {            private static class LazyHolder {            private static final Singleton6 INSTANCE = new Singleton6();            }            private Singleton6() {}            public static final Singleton6 getInstance() {                return LazyHolder.INSTANCE;            }        }        这种方式利用了JVM的类加载机制来保证初始化实例时的线程安全问题,但是它与方法3、4的区别是:方法3、          4只要在Singleton类被装载时instance就会被实例化。而方法6的Singleton类被装载时,LazyHolder并没有被          主动引用,所以不会实例化instance,当调用getInstance()方法时,LazyHolder被主动引用,故需要实例          化instance,这种方式既保证了实例懒加载,又保证了线程安全问题,相对比较合理。

问题与总结

 **问题**     问题1 如果单例由不同的类装载器装入,便有可能存在多个实例。例如,某些servlet容器对每个servlet使       用完全不同的类装载器,如果有两个servlet访问一个单例类,就会有各自的实例。     问题2 如果Singleton类实现了java.io.Serializable接口,该实例可能被序列化和反系列化。则反序列化       的多个对象,就会存在多个实例。     问题2的解决方法在《Effective Java》这本书中有提,即重写readResolve()方法,具体如下:     private Object readResolve() {               return INSTANCE;          } **总结**     单例模式为一个面向对象的应用程序提供了对象惟一的访问点,不管它实现何种功能,整个应用程序都应共享一       个实例对象。     对于单例模式的几种实现方式,需了解饿汉式和懒汉式的区别,线程安全与非线程安全的区别,类加载的时机,       以及懒汉式为了实现线程安全的几种方式的差别。
原创粉丝点击