java设计模式之单例模式

来源:互联网 发布:知乎装修精华帖 编辑:程序博客网 时间:2024/06/04 19:21

java设计模式参考文章:
Java设计模式实战,23种设计模式介绍以及在Java中的实现,Java设计模式, Java经典设计模式之五大创建型模式


## 定义 ##

单例模式是一种对象创建型模式,使用单例模式,可以保证为一个类只生成唯一的实例对象。也就是说,在整个程序空间中,该类只存在一个实例对象。其实,GoF对单例模式的定义是:保证一个类、只有一个实例存在,同时提供能对该实例加以访问的全局访问方法。 

## 代码示例 ##

/** * @author bwx * @date 2017/11/24 * 饿汉模式 * 如果只是加载这个类,而没有去获取该类的实例,会造成资源浪费 */public class HungerSingleton {    private static final HungerSingleton instance = new HungerSingleton();    private HungerSingleton() {}    public static  HungerSingleton getInstance() {        return instance;    }}/** * @author bwx * @date 2017/11/24 * 懒汉模式 * 问题: 每次调用getInstance都要同步(synchronized), 效率降低 */public class LazySingleton {    private static LazySingleton instance;    private LazySingleton() {}    public static synchronized LazySingleton getInstance() {        if (instance == null) {            instance = new LazySingleton();        }        return instance;    }}/** * @author bwx * @date 2017/11/24 */public class DoubleCheckSingleton {    private static volatile DoubleCheckSingleton instance;    private DoubleCheckSingleton() {}    public static DoubleCheckSingleton getInstance() {        if (instance == null) {            synchronized (DoubleCheckSingleton.class) {                if (instance == null) {                    instance = new DoubleCheckSingleton();                }            }        }        return instance;    }}/** * @author bwx * @date 2017/11/24 * 静态内部类实现单例 */public class StaticInnerSingleton {    /**     * 外部类没有static属性, 因此加载本类时不会立即初始化对象     */    private static class InnerClassInstance {        private static final StaticInnerSingleton instance = new StaticInnerSingleton();    }    private StaticInnerSingleton() {}    /**     * 只有真正调用getInstance方法时, 才会加载静态内部类(延迟加载),     * 而且加载类是天然的线程安全的(线程安全), 没有synchronized(调用效率高)     * @return     */    public static StaticInnerSingleton getInstance() {        return InnerClassInstance.instance;    }}

## 优点 ##

单例模式的类唯一实例由其本身控制,可以很好的控制用户何时访问它。

## 缺点 ##
## 解析 ##

在多线程中,可以直接把getInstance()设置为同步的(synchronized),但是并不高效,只能有一个线程可以调用这个方法,其余的会排队等待。所以整个方法做同步不是优解,那就只同步代码块就好了。这就引出了双重检验锁,即在同步块外检查一次null,然后再在同步块内检查一次。[但是最终这种方式也是会有问题的](https://www.zhihu.com/question/55439020),使用静态内部类或者枚举类是一种比较好的方式。
原创粉丝点击