美文网首页
Java设计模式之单例

Java设计模式之单例

作者: Sean1225 | 来源:发表于2019-03-16 10:30 被阅读0次

    单例,顾名思义,就是整个进程运行过程中只有一个实例,单例对象的特征一般如下:

    1. 生命周期较长,通常在进程结束前都不需要释放;或者使用频率很高,反复创建不如牺少量内存来换取性能。
    2. 避免对共享资源的多重占用。

    Java中实现单例一般有饿汉式和懒汉式两种主要方式。其中懒汉式又有多种拓展做法,如双重检测式、静态内部类式、枚举式等。

    饿汉式

    指在对象没有被使用到的时候创建。写法如下:

    public class Singleton {
        private static final Singleton INSTANCE = new Singleton();
        
        public static getInstance() {
            return INSTANCE;
        }
        
        private Singleton() {
            
        }
    }
    

    这种方式利用了类加载过程是唯一的并且安全的特性,但这种方式也有以下的限制或弊端:

    1. 构造函数不能带参数,或者参数本身不需要外界上下文信息。
    2. 可以使用反射创建多个对象。
    3. 如果对象始终没有被使用到(类使用到了),则白白浪费了内存。

    另外这种实现方法还有一种变体,就是在类静态代码块中实例化对象。

    懒汉式

    public class Singleton {
        private static Singleton sInstance;
        
        public synchronized static getInstance(Context context) {
            if(sInstance == null) {
                sInstance = new Singleton(context);
            }
            return sInstance;
        }
        
        private Singleton(Context context) {
            
        }
    }
    

    这种写法的优点是在使用时才创建对象,避免了内存浪费,但也存在以下限制或弊端:

    1. 可以使用反射创建多个对象。
    2. 每次调用getInstance()方法都要加锁,在高并发访问中会降低效率,为了改进这个问题,便有了双重检测式的出现。

    双重检测

    public class Singleton {
        private static Singleton sInstance;
        
        public static getInstance(Context context) {
            if(sInstance == null) {
                synchronized(Singleton.class) {
                    if(sInstance == null) {
                        sInstance = new Singleton(context);
                    }
                }
            }
            return sInstance;
        }
        
        private Singleton(Context context) {
            
        }
    }
    

    这种实现方式只有当对象未实例化前会加锁,提高了访问效率,但也存在以下限制或弊端:

    1. 可以使用反射创建多个对象。

    静态内部类

    这种方法是饿汉式的优化,采用了和饿汉式相同的原理同时又保证不会浪费内存,具体实现如下:

    public class Singleton {
        
        public static getInstance() {
            return Inner.INSTANCE;
        }
        
        private Singleton() {
            
        }
        
        private static class Inner {
            static final Singleton INSTANCE = new Singleton();
        }
    }
    

    这种方式有以下的限制或弊端:

    1. 构造函数不能带参数,或者参数本身不需要外界上下文信息。
    2. 可以使用反射创建多个对象。

    枚举

    使用枚举的好处是不能通过反射实例化对象,原因是枚举类实际上是一个抽象类,比如

    public enum Singleton {}
    

    相当于

    public abstract class Singleton extends Enum {}
    

    抽象类是不能被实例化,即使是用反射也一样。枚举的实现方法如下:

    public enum Singleton {
        INSTANCE;
        
        private Singleton() {
            
        }
    }
    

    使用这种方法的缺陷是:

    1. 如果构造函数需要传入不是常量的参数则无法使用。

    抽象类匿名子类

    这种方式也是用来解决反射问题的,从枚举式中得到的灵感,网络上提到这种方式的文章较少。实现方法如下:

    public abstract class Singleton {
        private static Singleton sInstance;
    
        public synchronized static Singleton getInstance(Context context) {
            if(sInstance == null) {
                sInstance = new Singleton(context) {};
            }
            return sInstance;
        }
    
        private Singleton(Context context) {
    
        }
    }
    

    这种方式完美解决了各种问题,这里又使用了懒汉式,也可以替换成其他实现方式。

    相关文章

      网友评论

          本文标题:Java设计模式之单例

          本文链接:https://www.haomeiwen.com/subject/hupjmqtx.html