设计模式之单例模式

Posted amcomputer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之单例模式相关的知识,希望对你有一定的参考价值。

1 背景回顾

设计模式是一种思维方式,前人总结的最佳实践,也是一种态度,一种进步。
软件过程里面设计模式一共有23种,一般分为3类。即创建型,结构性型,行为型。其中:
**创建型5种: ** 解决了创建对象的烦恼
单例模式,工厂模式,抽象工厂模式,建造者模式,原型模式

结构性型7种: 解决了如何让类组合起来完成复杂的功能
适配器模式,桥接模式,装饰模式,组合模式,外观模式,享元模式,代理模式,

**行为型11种:**解决了类之间的控制关系。
模版方法模式,命令模式,迭代器模式,观察者模式,中介者模式,备忘录模式,状态模式,策略模式,职责链模式,访问者模式,解释器模式。

如果想要学习并掌握这些设计模式,最后是编码和画图理解。

2 单例模式

单例模式比较好理解,一个类只有一个instance。关键是利用类加载器和构造方法私有。具体实现方法一般有2种。

饿汉式:在内存的方法区先new一个对象,然后直接返回。
懒汉式:调用时在返回
双重检测机制:适合多线程场景

3 饿汉式

package com.yang.create.single;


}

public class  Hungry{
    private Hungry() {
    }

    private static final Hungry HUNGRY = new Hungry();
    public static Hungry getInstance(){
        return HUNGRY;
    }



    public static void main(String[] args) {
        Hungry instance = Hungry.getInstance();
        Hungry instance2 = new Hungry();
        Hungry instance3 = new Hungry();
        System.out.println(instance.hashCode());
        System.out.println(instance2.hashCode());
        System.out.println(instance3.hashCode());
    }
}

类内输出结果:
在这里插入图片描述
发现不仅能输出不同的对象,还能使用new 来产生对象(思考:为什么已经构造器私有化了,还能new出对象,后面会解答)

类外或者包外输出结果:
在这里插入图片描述
分析:hashcode一样,在类外使用new关键字时报错。说明达到实验效果,需要注意的是类内依旧可以new,涉及到访问权限问题。

4 懒汉式

  class  Lazyman{
        private Lazyman() {
         }

         private  static Lazyman LAZYMAN =null;

         public static Lazyman getInstance(){
             if( LAZYMAN == null ){
                 LAZYMAN = new Lazyman();
             }
             return LAZYMAN;
         }
         }

多线程时,可能会不安全。我开启了200个线程(10个也试过),会导致线程开启失败。
在这里插入图片描述

思考:为什么前者是安全的,到了懒汉式,却不安全了?

因为少了final关键词,动态生成LAZYMAN

5 双重检测机制

package com.yang.create.single;

public class  DoubleLock {
    private DoubleLock() {
        System.out.println(Thread.currentThread().getName() + "oK");
    }

    private static DoubleLock LAZYMAN = null;

    public static DoubleLock getInstance() {
        //双层检测
        if (LAZYMAN == null) {
            synchronized (LAZYMAN.getClass()) {//第一层 加锁
                if (LAZYMAN == null) {//第2层
                    LAZYMAN = new DoubleLock();  //不是原子操作,第一步先分配内存,第二步执行构造方法,第3步指向内存空间
                }
            }


        }
        return LAZYMAN;
    }


}



结果:
在这里插入图片描述

因为 LAZYMAN = new DoubleLock(); //不是原子操作,第一步先分配内存,第二步执行构造方法,第3步指向内存空间
所以导致异常,多线程下,3个步骤会被打乱。
所以需要加上防止指令重排操作:volatile
private volatile static DoubleLock LAZYMAN = null;

package com.yang.create.single;

public class  DoubleLock {
    private DoubleLock() {
        System.out.println(Thread.currentThread().getName() + "oK");
    }

    private volatile  static DoubleLock LAZYMAN = null;

    public static DoubleLock getInstance() {
        //双层检测
        if (LAZYMAN == null) {
            synchronized (DoubleLock.class) {//第一层 加锁
                if (LAZYMAN == null) {//第2层
                    LAZYMAN = new DoubleLock();  //不是原子操作,第一步先分配内存,第二步执行构造方法,第3步指向内存空间
                }
            }


        }
        return LAZYMAN;
    }


}



测试成功:
在这里插入图片描述
当然,如果使用反射,也会破坏单例模式。这里可以使用enum,即枚举类型来构造单例,enum是一个特殊的java类。

以上是关于设计模式之单例模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之单例模式

Java设计模式之单例模式

设计模式之单例模式以及简单代码实现

设计模式之单例设计模式

设计模式之单例模式

设计模式之单例模式