单例模式的学习总结

版权声明:转载请标明原作者及地址 https://blog.csdn.net/cauchy6317/article/details/83212288

什么是单例模式?单例模式的作用是什么?单例模式如何实现?

Java语言中的对象都是通过类产生,如果没有类,就没有类的具体对象。那么,有类以后,我们就可以通过类产生很多实例对象。但是,有时候我们只需要该类产生且只能产生唯一的一个对象。比如,我的系统时间对象。因为这些对象在现实的需求中是被要求唯一的,而且这些对象的创建很耗费内存。对于这些对象的实现模式,我们称为单例模式。(笔者个人理解)

饿汉式:


/**
 * @author chengjun
 * @date 2018/10/11 21:19
 * 单例模式——饿汉式(饿汉式顾名思义,不管程序实际运行的过程中需不需要此单例,该单利都会被创建)
 */
public class SingletonHungryMode {
//    这个单例模式的实例只能被内部的静态方法调用,所以要用static和private 修饰
    private static SingletonHungryMode HUNGRYMODE = new SingletonHungryMode();

//    将构造器私有化是为了让该单例模式在外部无法被new出来
    private SingletonHungryMode(){};

//    提供一个公开的静态方法(类方法),让外部获取该单例模式的实例对象
    public static SingletonHungryMode getHUNGRYMODE() {
        return HUNGRYMODE;
    }

}

class test{
    public static void main(String[] args) {
        SingletonHungryMode singletonHungryMode0 = SingletonHungryMode.getHUNGRYMODE();
        SingletonHungryMode singletonHungryMode1 = SingletonHungryMode.getHUNGRYMODE();
        System.out.println(singletonHungryMode0==singletonHungryMode1);//true
    }
}

由于静态方法只能访问到静态变量,所以单例的实例对象要被static关键字修饰。

懒汉式:

/**
 * @author chengjun
 * @date 2018/10/20 12:26
 * 单例模式——懒汉式(懒汉式顾名思义,在程序实际运行的过程中需要此单例,该单利才会被创建)
 */
public class SingletonLazyMode {
    //这个单例模式的实例只能被内部的静态方法调用,所以要用static和private 修饰
    private static SingletonLazyMode LAZYMODE;

    //将构造器私有化是为了让该单例模式在外部无法被new出来
    private SingletonLazyMode(){}

    //提供一个公开的静态方法(类方法),让外部获取该单例模式的实例对象
    public static SingletonLazyMode getInstance(){
        //获取单例对象时,判断该单例的实例对象是否为空
        if(LAZYMODE == null){
            LAZYMODE = new SingletonLazyMode();
        }
        return LAZYMODE;
    }
}

这样在多线程的情况下,又看可能产生多个单例实例对象。

多线程下的单例模式:


public class SingletonLazyMode {
    //这个单例模式的实例只能被内部的静态方法调用,所以要用static和private 修饰
    private static SingletonLazyMode LAZYMODE;

    //将构造器私有化是为了让该单例模式在外部无法被new出来
    private SingletonLazyMode(){}

    //提供一个公开的静态方法(类方法),让外部获取该单例模式的实例对象
    public static SingletonLazyMode getInstance(){
        //当线程运行到这里,会把SingletonLazyMode.class 锁起来,但是,每次线程过来都会被锁起来,降低了性能
        //就是当线程A,线程B都过来了,线程A获得锁以后,线程B需要等待(性能降低)
        synchronized (SingletonLazyMode.class){
            //获取单例对象时,判断该单例的实例对象是否为空
            if(LAZYMODE == null){
                LAZYMODE = new SingletonLazyMode();
            }
        }
        return LAZYMODE;
    }
}

这样可以避免多线程下创建多个单例的实例对象,但是,锁机制在避免多线程创建实例对象的同时,也在获取此单例对象的过程加上了锁。所以对多线程获取该实例对象时,性能降低了很多。那么,我们要用到接下来的双重校验机制。

多线程的双重校验模式:


public class SingletonLazyMode {
    //这个单例模式的实例只能被内部的静态方法调用,所以要用static和private 修饰
    private static SingletonLazyMode LAZYMODE;

    //将构造器私有化是为了让该单例模式在外部无法被new出来
    private SingletonLazyMode(){}

    //提供一个公开的静态方法(类方法),让外部获取该单例模式的实例对象
    public static SingletonLazyMode getInstance(){
        //通过在这里判空,可以在除了第一次创建实例对象以后,多线程获取该实例对象时避免锁机制
        if(LAZYMODE == null){
            //当线程运行到这里,会把SingletonLazyMode.class 锁起来,但是,每次线程过来都会被锁起来,降低了性能
            //就是当线程A,线程B都过来了,线程A获得锁以后,线程B需要等待(性能降低)
            synchronized (SingletonLazyMode.class){
                //获取单例对象时,判断该单例的实例对象是否为空
                if(LAZYMODE == null){
                    LAZYMODE = new SingletonLazyMode();
                }
            }
        }
        return LAZYMODE;
    }
}

在这里双重校验机制的好处在于,除了第一次创建该实例对象的时候,线程会加上锁,以后的获取过程避免了锁机制。

静态内部类模式:

扫描二维码关注公众号,回复: 3692688 查看本文章

Java虚拟机加载静态内部类的线程是安全的。但是,不能防止反序列化。


public class SingletonLazyMode {

    //将构造器私有化是为了让该单例模式在外部无法被new出来
    private SingletonLazyMode(){}

    //jvm加载类的过程是线程安全的,避免了首次加载创建该实例对象的多线程情况。从而保证了只创建一个实例对象
    private static class SingletonLazyModeHandler{
        private static SingletonLazyMode INSTANCE = new SingletonLazyMode();
    }
    //提供一个公开的静态方法(类方法),让外部获取该单例模式的实例对象
    public static SingletonLazyMode getInstance(){
        return SingletonLazyModeHandler.INSTANCE;
    }
}

枚举模式:

实现了静态内部类的优点,同时防止了反序列化。

/**
 * 利用枚举的方式实现单例,Android不推荐
 */
public enum  EnumMode {

    INSTANCE;

    private int id;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

总结:一般简单实现使用饿汉式;延迟加载使用静态内部类模式;防止反序列化使用枚举模式;对单例模式的创建过程进行控制的使用双重校验模式。

猜你喜欢

转载自blog.csdn.net/cauchy6317/article/details/83212288