Java初级 --单例模式

  • 什么是单例模式 ?
    单例模式(SingleTon Pattern)是最简单的一种设计模式。
    单例模式的英文原话是 :

Ensure a class has only one instance,and provided a global point of access to it.

意思是 :确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
  • 单例模式有哪些要求?
    1、单例类只能有一个实例;
    2、单例类必须自己创建自己的唯一实例;
    3、单例类必须给所有其他对象提供这一实例。
  • 单例模式的应用场景
    单例模式的作用是确保一个类只有一个实例存在
    可以用在:
    创建目录、数据库连接需要单线程操作的场合,用于实现对系统资源的控制。
    一个类可以定义无数个对象,但是只能有一个实例
  • 在 Java 中实现单例模式通常有两种表现形式:
    1、饿汉式单例类(类加载时,就进行对象实例化)
package test.java.hsdaihd;
public class SingleTon1 {
    //类加载时,就进行对象实例化
    private static SingleTon1 m_instance = new SingleTon1();
    /**
     * 构造函数私有,保证外界无法直接实例化
     */
    private SingleTon1(){

    }
    /**
     * 通过该方法获得实例对象(提供一个全局的访问点)
     * @return
     */
    public static SingleTon1 getInstance(){
        return m_instance;
    }
    public static void main(String[] args) {
        SingleTon1 singleTon1 = SingleTon1.getInstance();
         SingleTon1 singleTon2 = SingleTon1.getInstance();
        SingleTon1 singleTon3 = SingleTon1.getInstance();
        System.out.println(singleTon1);
        System.out.println(singleTon2);
        System.out.println(singleTon3);
    }
}

可见此时该类只出现了一个实例
可见此时该类只出现了一个实例
2、懒汉式单例类(第一次引用类时,才进行对象实例化)
在这里插入图片描述
懒汉式单例类与饿汉式单例类相同的是,类的构造函数是私有的;不同的是,懒汉式单例类在加载时不会将自己实例化,而是在第一次被调用时将自己实例化。
SingleTon2 中 main 函数内容与SingleTon1同理,我们可以看到,很奇怪,为什么该类产生的不是一个实例,而是多个呢?

是因为在多线程环境下,线程 **A** 和线程 **B** 同时调用此方法,则执行if(m_instance == null)语句时都为真,那么线程A和线程B都会创建一个对象,在内存中就会有两个对象,这样就违反了单例模式。


那么如何来解决这一问题呢 ?就看接下来线程安全的单例模式。
  • 线程安全的单例模式
package test.java.hsdaihd;

public class SingleTon2 {
    private static Object lock = new Object();
    private static SingleTon2 m_instance = null;

    /**
     * 构造方法私有,保证外界无法直接实例化
     */
    private SingleTon2(){

    }

    /**
     * 提供一个全局的访问点
     * @return
     */
    public static SingleTon2 getInstance(){
        synchronized(lock) {
            if (m_instance == null) {
                m_instance = new SingleTon2();
            }
        }
        return m_instance;
    }
    public static void main(String[] args) {
        SingleTon2 singleTon1 = SingleTon2.getInstance();
        SingleTon2 singleTon2 = SingleTon2.getInstance();
        SingleTon2 singleTon3 = SingleTon2.getInstance();
        System.out.println(singleTon1);
        System.out.println(singleTon2);
        System.out.println(singleTon3);
    }
}

上述代码中,我们给if(m_instance == null) 外加了一个synchronized 的同步对象锁,这个时候该类就只有一个实例了。

亲爱的小伙伴们,这样做真的好吗?(高效 ?)我们来分析一下。

在这里插入图片描述
每一个线程,不管是否为 null ,都要加一次锁,而加锁、放锁都会消耗 CPU 资源,线程一多,会使资源浪费严重。

那么该如何解决呢?

在这里插入图片描述
先判断后加锁 ?确定吗 ?
在这里插入图片描述

明显违背了单例模式原则,那么我们该怎么办呢?不用怕,来~看~

在这里插入图片描述
这样做既防止了多线程资源浪费严重,又满足了一个类只有一个实例。这就是双重校验

  • 内部类实现单例模式
    我们选择静态内部类来实现单例模式。
package test.java.hsdaihd;

public class StaticSingleTon {
    private StaticSingleTon(){

    }
    private static class SingleTon3 {
         public static StaticSingleTon c = new StaticSingleTon();
    }
    public static StaticSingleTon getInstance(){
        return SingleTon3.c;
    }

    public static void main(String[] args) {
        StaticSingleTon staticSingleTon1 = StaticSingleTon.getInstance();
        StaticSingleTon staticSingleTon2 = StaticSingleTon.getInstance();
        StaticSingleTon staticSingleTon3 = StaticSingleTon.getInstance();
        System.out.println(staticSingleTon1);
        System.out.println(staticSingleTon2);
        System.out.println(staticSingleTon3);
    }
}

在这里插入图片描述

  • 枚举实现单例模式

  • 参考文献 《设计模式(Java版)》 韩静海编

猜你喜欢

转载自blog.csdn.net/xyxy66/article/details/83584829
0条评论
添加一条新回复