设计模式—单例模式(学习笔记)

作用

  • 单例模式保证了 系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,单例模式可以提高系统性能。
  • 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new。

使用场景:

1、创建和销毁频繁。
2、对象过大,重量级,但是常用,频繁访问-工具类、数据源、session工厂等。

饿汉式(静态变量):

原理:
    1、私有化构造器(防止new)
    2、内部属性创建对象,随类而生(唯一性)
    3、提供公有静态方法,返回对象(外部可使用)
优点:写法简单,类装载时期完成实例化,避免线程同步问题
缺点:不可懒加载,除非保证系统中会使用到,否则造成资源浪费
总结:可用,但是有可能造成内存浪费。
public class Hungre1 {

    public static void main(String[] args) {
        // 除去getInstance()还有其他装载方式可能浪费内存
        Singleton singleton = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton.equals(singleton2));
    }
}

/**
 * (静态常量)
 */
class Singleton {
    /**
     * 1、构造器私有化,外部无法new
     */
    private Singleton() {
    }

    /**
     * 2、本类内部创建对象实例
     */
    private final static Singleton INSTANCE = new Singleton();

    /**
     * 3、对外提供一个公有的静态方法,返回实例对象
     */
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

饿汉式(静态代码块):

原理:将类中创建操作放置在static{}中,其余同上。
public class Hungre2 {

    public static void main(String[] args) {
        // 随类加载创建,可能内存浪费
        Singleton2 singleton = Singleton2.getInstance();
        Singleton2 singleton2 = Singleton2.getInstance();
        System.out.println(singleton.equals(singleton2));
    }
}

/**
 * (静态变量)
 */
class Singleton2 {

    static {
        instance = new Singleton2();
    }
    /**
     * 1、构造器私有化,外部无法new
     */
    private Singleton2() {}
    /**
     * 2、本类内部创建对象实例
     */
    private final static Singleton2 instance;

    /**
     * 3、对外提供一个公有的静态方法,返回实例对象
     */
    public static Singleton2 getInstance() {
        return instance;
    }
}

懒汉式(线程不安全):

原理:
    1、私有化构造器(防止new)
    2、提供公有静态方法创建并返回对象(外部可使用)
    3、在创建方法中确保对象只有一个(唯一性),但无法保证线程安全问题
优点:懒加载,解决资源浪费问题。
缺点:多线程模式下可能产生多个实例。
总结:不安全,不建议使用。
public class Lazy1 {
    public static void main(String[] args) {
        Singleton3 singleton = Singleton3.getInstance();
        Singleton3 singleton2 = Singleton3.getInstance();
        System.out.println(singleton.equals(singleton2));
    }
}

class Singleton3 {

    private static Singleton3 instance;

    /**
     * 私有化构造器
     */
    private Singleton3() {}

    /**
     * 提供一个静态的公有方法,当使用到该方法时,才来创建对象。
     * @return 实例对象
     */
    public static Singleton3 getInstance() {
        if (null == instance) {
            instance = new Singleton3();
        }
        return instance;
    }
}

懒汉式(线程安全,同步方法):

原理:
    1、私有化构造器(防止new)
    2、提供公有静态方法创建并返回对象(外部可使用)
    3、在创建方法中确保对象只有一个(唯一性),synchronized锁方法解决同步安全问题
优点:解决线程安全问题。
缺点:锁方法导致性能问题,每次调用创建方法都会加锁,包括已经实力化对象后。
总结:性能低,不建议使用。
public class Lazy3 {
    public static void main(String[] args) {
        Singleton3 singleton = Singleton3.getInstance();
        Singleton3 singleton2 = Singleton3.getInstance();
        System.out.println(singleton.equals(singleton2));
    }
}

class Singleton5 {

    private static Singleton5 instance;

    /**
     * 私有化构造器
     */
    private Singleton5() {}

    /**
     * 提供一个静态的公有方法,当使用到该方法时,才来创建对象。
     * @return 实例对象
     */
    public static synchronized Singleton5 getInstance() {
        if (null == instance) {
            instance = new Singleton5();
        }
        return instance;
    }
}

双重检查:

原理:
    1、私有化构造器(防止new)
    2、提供公有静态方法,加入双重检测(外部可使用、唯一性)
优点:解决了线程安全(双重检测)、懒加载(get方法)问题。
总结:推荐使用。
public class DoubleCheck {

    public static void main(String[] args) {
        Singleton6 singleton = Singleton6.getInstance();
        Singleton6 singleton2 = Singleton6.getInstance();
        System.out.println(singleton.equals(singleton2));
    }
}

class Singleton6 {
    private Singleton6() {}

    /**
     * volatile 全局可见
     */
    private static volatile Singleton6 singleton6;

    public static Singleton6 getInstance() {
        if (singleton6 == null) {
            synchronized (Singleton6.class) {
                if (singleton6 == null) {
                    singleton6 = new Singleton6();
                }
            }
        }
        return singleton6;
    }
}

静态内部类:

原理:
    1、私有化构造器(防止new)
    2、静态内部类创建方法(懒加载)
    3、提供公有静态方法调用静态内部类(外部可使用)
    4、静态属性只会在第一次加载类时初始化,该唯一性由JVM保证(唯一性)
优点:避免线程不安全、静态内部类实现延迟加载、效率高。
总结:推荐使用。
public class StaticInside {

    public static void main(String[] args) {
        Singleton7 singleton1 = Singleton7.getInstance();
        Singleton7 singleton2 = Singleton7.getInstance();
        System.out.println(singleton1.equals(singleton2));
    }
}

class Singleton7 {

    // 构造器私有化
    private Singleton7() {}
    // 静态内部类,需要一个静态属性 外部类加载时不会被加载
    private static class SingletonInstance {
        private static final Singleton7 INSTANCE = new Singleton7();
    }
    public static Singleton7 getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

枚举:

原理:
    1、枚举反编译后:public static final 枚举类 ENUM_CLASS;(final修饰的对象地址值不变,确保只有一个)
    2、私有化构造器(防止new)
优点:简单快捷安全高效。
总结:推荐使用。 - Josh Bloch(Effective Java作者)。
public class Enum {
    public static void main(String[] args) {
        Singleton8 instance1 = Singleton8.INSTANCE;
        Singleton8 instance2 = Singleton8.INSTANCE;
        System.out.println(instance1.equals(instance2));
    }
}

enum Singleton8 {
    INSTANCE;
}

注:文章内容学习自bilibili-尚硅谷,转载请注明出处。**

你可能感兴趣的:(设计模式—单例模式(学习笔记))