设计模式笔记———单例模式

一、定义

单例模式:这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注意:

  1. 单例类只能有一个实例
  2. 2.单例类必须自己创建自己的唯一实例
  3. 3.单例类必须为其他对象提供这唯一实例

二、代码实现

  1. 饿汉式

/**
 1. 饿汉式
 */
public class Singleton1 {
    private Singleton1(){};
    private static Singleton1 instance = new Singleton1();
    public static Singleton1 getInstance(){
        System.out.println("加载饿汉式");
        return instance;
    }
}
  1. 懒汉式
/**
 1. 懒汉式
 */
public class Singleton2 {
    private Singleton2() {
    }
    private static Singleton2 instance;
    public static Singleton2 getInstance(){
        if (instance==null){
       		System.out.println("懒汉式")
            instance = new Singleton2();
        }
        return instance;
    }
}

三、懒汉式与饿汉式区别

  1. 饿汉式:
/**
      *是否 Lazy 初始化:否
      *是否多线程安全:是
      *实现难度:易
      *描述:这种方式比较常用,但容易产生垃圾对象。
      *优点:没有加锁,执行效率会提高。
      *缺点:类加载时就初始化,浪费内存。
      *它基于 classloder 机制避免了多线程的同步问题,
      * 不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,
     * 在单例模式中大多数都是调用 getInstance 方法,
      * 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,
      * 这时候初始化 instance 显然没有达到 lazy loading 的效果。
      */

懒汉式:

/**
      *是否 Lazy 初始化:是
      *是否多线程安全:否
      *实现难度:易
      *描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。
      *因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
      *这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。
      */
  1. 饿汉式天生线程安全,可以直接用于多线程而不会出现问题;
    懒汉式本身并非线程安全,为了实现线程安全有几种写法。
    如:
/**
 * 线程安全懒汉式
 */
public class Singleton3 {
    private Singleton3() {
    }
    private static Singleton3 instance;
    public static synchronized Singleton3 getInstance(){
        if (instance==null){
            return new Singleton3();
        }
        return instance;
    }
}

/**
 * 线程安全懒汉式第二种写法
 */
public class Singleton4 {
    //私有化构造方法,防止外界调用,保证对象是单例对象
    private Singleton4(){};
    
    // 私有化静态变量,防止外界修改,没有实例化
    private static Singleton4 instance;
    
    //提供方法给外界调用获得单例对象
    //当多个线程都在调用此方法是时,必须只有一个单例对象生成,
    //这里采用加上同步代码块
    public static Singleton4 getInstance(){
        if (instance==null){
            //静态方法,是当前类为进程锁
            synchronized(Singleton4.class){
                return new Singleton4();
            }
        }
        return instance;
    }
}

如果不想加锁,又不想太过于消耗内存,可以

public class Singleton5 {
/**
 1. 折中写法,不加锁(即保证线程安全)也不太消耗内存
 2. (饿汉式消耗内存,懒汉式不保证线程安全)
 3. 
 4. 这个时候就需要一个内部类作为桥梁了,当getInstance()时,
 5. 类加载器才会去加载Nested,然后实例化Singleton的实例
 */
    private Singleton5(){

    }

    public static Singleton5 getInstance(){
        return Nested.singleton;
    }

    public static class Nested{
        static {
            System.out.println("蛤蛤");
        }
        private static Singleton5 singleton = new Singleton5();
    }
}
  1. 资源加载和性能
    饿汉式在创建时就实例化出一个静态对象,不管会不会使用这个对象,都会占据一定内存,但是对应的,在第一次调用时速度也会快很多,因为其资源已经完成初始化。
    懒汉式有延迟加载,在第一次使用该实例才会实例化对象出来,第一次调用时要做初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样。
posted @ 2021-07-27 00:01  TellMeYourStory  阅读(36)  评论(0)    收藏  举报