虫虫的技术博客 技术 生活

Tuesday, May 7, 2019

设计模式-单例模式

        设计模式,通常指GOF的《设计模式 可复用面向对象软件的基础》书中提到的面向对象编程23种设计模式,话不多说,先来看一个单例模式。

单例模式,可以保证在系统中单例类只能有一个实例。

接下来我把在网上流行的大部分实现方案以及个人在思考单例模式的实现过程整理如下
方案一:

/**
 * 饿汉式
 * 使用时直接使用静态变量,理念不好,不利于扩展
 */
public class Singleton {
    /**
     * 初始化动作写到静态代码块中是一样的效果
     */
    public static Singleton instance = new Singleton();

    private Singleton() {
    }
}


方案二:

/**
 * 饿汉式
 * 使用时调用 getInstance 方法,后期如有需求可直接改动方法实现即可
 */
public class Singleton {
    public static Singleton instance = new Singleton();

    private Singleton() {
    }

    public static Singleton getInstance() {
        return instance;
    }
}


方案三:

/**
 * 懒汉式,使用时才初始化
 * 线程不安全,单线程环境下可用
 */
public class Singleton {
    public static Singleton instance = null;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
} 


方案四:

/**
 * 懒汉式,使用时才初始化
 * 线程安全,方法加锁,效率低
 */
public class Singleton {
    public static Singleton instance = null;

    private Singleton() {
    }

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
 

方案五:

/**
 * 懒汉式,使用时才初始化
 * 线程安全,代码块加锁,效率高,
 */
public class Singleton {
    /**
     * 这里如果不加volatile声明,可能会因为JVM对指令重排导致异常
     */
    public static volatile Singleton instance = null;

    private Singleton() {
    }

    /**
     * 这里如果只判断里层,那和方法加锁一样了,如果只判断外层,那线程安全的问题没有解决
     * 这种方案可能在实例初始化时,如果遇到多线程问题,会有资源竞争,
     * @return
     */
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}


方案六:

/**
 * 静态内部类实现,针对内部类SingletonHolder来看,属于饿汉式,针对外部类Singleton来看,属于懒汉式的效果
 * 只有在调用getInstance方法的时候才会初始化内部类SingletonHolder的属性也就是单例实例
 * 由JVM帮我们保证了线程安全,JVM在初始化类的时候是不允许多线程进入的
 */
public class Singleton {
    public static String someStaticProperty = null;

    private Singleton() {
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }

    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
}
 

方案七:

/**
 * 用枚举来实现单例,有很多优点,无需考虑线程安全问题,还可以防止反序列化重新创建对象。
 * 枚举来作为单例的实现方案最初看到是在EffactiveJava中提出的,但没有被普遍使用该方案
 * 个人认为原因,枚举出来的比较晚,大家不是很熟悉,枚举是属于懒汉式
 * 对枚举的解读参考文章:https://www.cnblogs.com/kailejun/p/6624471.html
 */
public enum Singleton {
    INSTANCE;

    public void someMethod() {

    }
}


代码地址:
https://github.com/angelala00/learn/tree/master/src/main/java/cn/jc/designpattern/singleton

方案五和方案六是多线程环境下用的最普遍的两种方案,大部分人更认可的是方案六。

JDK中单例模式的身影:
java.long.Runtime

前提知识,面向对象编程

0 comments:

Post a Comment

Popular Posts

Copyright © 虫虫的成长历程 | Powered by Blogger Design by PWT | Blogger Theme by NewBloggerThemes.com