设计模式-创建型之单例模式

前言
  • 什么是单例
    – 在应用的整个生命周期周期中只有一个实例对象。
  • 应用场景及好处
    – 对于一些频繁创建的对象、或者创建对象耗时过多,对象占用内存大,而且频繁使用的对象、工具类等,我们可以使用单例模式,这样能够节省资源以及提升系统性能。
单例之恶汉模式
  • 静态常量方式
package com.dason.singleton.evilman.typeone;

public class EvilManOne {

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

class Singleton{

    // 私有构造
    private void Singleton(){}

    // 私有静态常量
    private final static Singleton instance = new Singleton();

    // 公共静态获取方法
    public static Singleton getInstance(){
        return instance;
    }
}
  • 静态代码块方式
package com.dason.singleton.evilman.typetwo;

public class EvilManwo {

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

class Singleton{

    // 私有构造
    private void Singleton(){}

    // 私有静态常量
    private static Singleton instance = null;
    
    // 静态代码块
    static {
        instance = new Singleton();
    }

    // 公共静态获取方法
    public static Singleton getInstance(){
        return instance;
    }
}
恶汉模式优缺点

优点:利用类加载线程安全机制来进行实例化,从而达到线程安全。
缺点:没有进行懒加载,当程序不曾使用时,其实是一种资源的浪费。

单例之懒汉模式
  • 线程不安全懒汉模式
package com.dason.singleton.lazyman.typeone;

public class LazyManOne {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance == instance2);
    }
}

class Singleton{

    // 私有构造
    private void Singleton(){}

    // 私有静态常量
    private static Singleton instance = null;

    // 公共静态获取方法
    // 懒加载,当第一次是使用的时候才创建,从而也带来新问题:线程不安全
    public static Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}
  • 线程安全懒加载模式-同步方法
package com.dason.singleton.lazyman.typetwo;

public class LazyManTwo {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance == instance2);
    }
}

class Singleton{

    // 私有构造
    private void Singleton(){}

    // 私有静态常量; volatile 来声明使其线程可见性
    private static volatile Singleton instance = null;

    // 公共静态同步获取方法
    // 懒加载,同步解决线程不安全问题
    //同步带来新的问题:并发时带来效率低
    public static synchronized Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}
  • 同步代码块懒加载-双检查方式
package com.dason.singleton.lazyman.typethree;

public class LazyManThree {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance == instance2);
    }
}

class Singleton{

    // 私有构造
    private void Singleton(){}

    // 私有静态常量; volatile 来声明线程的可见性
    private static volatile Singleton instance = null;

    // 公共静态同步代码块获取方法
    // 懒加载,同步代码块解决线程不安全问题
    public static Singleton getInstance(){
        if(instance == null){//没有该行判断也行,增加该判断大大提升并发时性能
            synchronized (Singleton.class){
                if(instance == null){//该行判断必须有,不然无法达到单例
                    instance = new Singleton();
                }
            }
        }

        return instance;
    }
}
  • 线程安全懒加载-静态内部类
package com.dason.singleton.lazyman.typefour;

public class LazyManFour {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance == instance2);
    }
}

class Singleton{

    // 私有构造
    private void Singleton(){}

    //私有的静态内部类:在类加载时,是不会加载类的静态内部类,从而达到懒加载
    // 线程安全:当第一次使用时,JVM加载静态内部类,JVM类加载是线程安全的,从而实例化对象
    private static class SingletonInstance {
        private static Singleton INSTANCE = new Singleton();
    }

    // 公共静态获取方法
    public static Singleton getInstance(){
        return SingletonInstance.INSTANCE;
    }
}
  • 线程安全-枚举
package com.dason.singleton.lazyman.typefive;

/**
 * @Author Dason
 * @CLASS LazyManFive
 * @DESC
 * @CreateTime 2019-08-23
 */
public class LazyManFive {
    public static void main(String[] args) {
        Singleton instance = Singleton.INSTANCE;
    }
}

// 使用枚举不仅能够解决线程安全问题,同时能够防止反序列化创建对象
enum Singleton{
    INSTANCE;
}

推荐使用:枚举方式、静态内部类、同步代码块(双重检查)

扩展:JVM类装载机制?enum是怎么防止反序列化创建对象?volatile是怎么保证线程内存可见性?

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值