设计模式~单列模式-01

简介: 单列模式1、饿汉式2、懒汉式(lazy loading)3、双重检测4、静态内部类

单列模式

1、饿汉式

2、懒汉式(lazy loading)

3、双重检测

4、静态内部类(完美)

5、枚举单列(最完美)


       单例模式就是为了确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。单例模式控制控制对象不要反复创建,提高我们工作的效率。减少资源的占用。

       【解释:我有 6 个漂亮的老婆,她们的老公都是我,我就是我们家里的老公 Sigleton,她们只要说道「老公」,都是指的同一个人,那就是我 。】

(1)单例模式下类的组成部分:

       1.私有的构造方法。

       2.私有的当前类对象作为静态属性。

       3.公有的向外界提供当前类对象的静态方法。

主要的两种实现方式:

       饿汉式:线程安全,调用效率高,不能延时加载。

       懒汉式:线程安全,调用效率不高,可以延时加载。

其他方式:

       双重检测锁式:极端情况下偶尔会出现问题,不建议使用。

       静态内部类式:线程安全,调用效率高,可以延时加载。

       枚举式:线程安全,调用效率高,不能延时加载。

2懒汉式饿汉式的区别

       “懒汉式”是在你真正用到的时候才去建这个单例对象“饿汉式”是在不管用不用得上,一开始就建立这个单例对象

       从实现方式来讲他们最大的区别就是懒汉式是延时加载,他是在需要的时候才创建对象,而饿汉式在虚拟机启动的时候就会创建,饿汉式无需关注多线程问题,写法简单明了,能用则用。但是它是加载类时创建实例。

       饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变。懒汉式如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的。

       只是一个语法的标识,就好比文档中的句号和逗号差不多,代表当前是一个完整的语句,和下一个语法分开,如果仅仅只有一句,加不加无所谓,但是多个语句时,要区分,否则编译器不知道你的语法。

1、饿汉式

       类加载到内存后,就实例化一个单例,JVM保证线程安全。

       简单实用,推荐使用!

       唯一缺点:不管用到与否,类装载时就完成实例化。

public class Singleton01 {
    //持有私有静态实例,防止被引用
private static final Singleton01 INSTANCE = new Singleton01();
//    private static final Singleton01 INSTANCE;
//    static {
//        INSTANCE = new Singleton01();
//    }
//私有构造方法,防止被实例化
//只有本类能调用,只能Singleton01 Singleton = Singleton01.getInstance();调用
private Singleton01() {};//分号:增加语法的可读性
/*只是一个语法的标识,就好比文档中的句号和逗号差不多,代表当前是一个完整的语句,和下一个语法分开,如果仅仅只有一句,加不加无所谓,但是多个语句时,要区分,否则编译器不知道你的语法。*/
//懒汉式,静态工程方法,创建实例
    public static Singleton01 getInstance() {
        return INSTANCE;
}
//可有可无
    public void m() {
        System.out.println("m");
    }
    public static void main(String[] args) {
        Singleton01 m1 = Singleton01.getInstance();
        Singleton01 m2 = Singleton01.getInstance();
        System.out.println(m1 == m2);
    }
}

2、懒汉式lazy loading

       虽然达到了按需初始化的目的,但却带来线程不安全的问题。

       可以通过synchronized解决,但也带来效率下降。延迟加载,也叫作懒加载,等到真正用的时候才加载。

public class Singleton02 {
//持有私有静态实例,防止被引用
    private static Singleton04 INSTANCE;
    //私有构造方法,防止被实例化
    private Singleton02() {
    }
    //懒汉式,静态工程方法,创建实例
    //加锁(synchronized)效率下降
    public static /*synchronized*/ Singleton02 getInstance() {
        if (INSTANCE == null) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //妄图通过减小同步代码块的方式提高效率,然后不可行
//            synchronized (Singleton02.class) {
//                try {
//                    Thread.sleep(1);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
            INSTANCE = new Singleton02();
        }
        return INSTANCE;
    }
    public void m() {
        System.out.println("m");
    }
    public static void main(String[] args) {
        for(int i=0; i<100; i++) {
            new Thread(()->{
                System.out.println(Singleton02.getInstance().hashCode());
            }).start();
        }
    }
}

3、双重检测

       保证线程安全;以前认为是最完美的方式。

public class Singleton03 {
    //volatile:不写,会出现。volatile 防止指令重排和可见性
    private static volatile Singleton03 INSTANCE; //JIT
    private Singleton03() {
    }
public static Singleton03 getInstance() {
//判断对象是否已经实例化,只有非实例化的情况下才能进入if块进行加锁。
        if (INSTANCE == null) {
            //双重检查:保证线程安全;以前认为是最完美的方式
            synchronized (Singleton03.class) {
//避免 SingletonTon== null时,第一个线程实例化后,进入阻塞状态的线程被唤醒后仍会进行实例化。
                if(INSTANCE == null) {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    INSTANCE = new Singleton03();
                }
            }
        }
        return INSTANCE;
    }
    public void m() {
        System.out.println("m");
    }
    public static void main(String[] args) {
        for(int i=0; i<100; i++) {
            new Thread(()->{
                System.out.println(Singleton03.getInstance().hashCode());
            }).start();
        }
    }
}

4、静态内部类(完美)

       静态内部类方式,完美。JVM保证单例线程安全,加载外部类时不会加载内部类,这样可以实现懒加载。

public class Singleton04 {//JVM只加载一次
//私有构造方法
    private Singleton04() {
    }
    //静态内部类,初始化04
private static class Singleton07Holder {
//组合外部类对象作为属性
        private final static Singleton04 INSTANCE = new Singleton04();//出现延迟加载
    }
    public static Singleton04 getInstance() {
        return Singleton04Holder.INSTANCE;
    }
    public void m() {
        System.out.println("m");
    }
    public static void main(String[] args) {
        for(int i=0; i<100; i++) {
            new Thread(()->{
                System.out.println(Singleton04.getInstance().hashCode());
            }).start();
        }
    }
}

5、枚举单列最完美

       不仅可以解决线程同步,还可以防止反序列化。由JVM从根本上提供保障!避免通过反射和反序列化的漏洞!

public enum Singletontonton05 {
    INSTANCE;
    public void m() {}
    public static void main(String[] args) {
        for(int i=0; i<100; i++) {
            new Thread(()->{
                System.out.println(Singletonton05.INSTANCE.hashCode());
            }).start();
        }
    }
}


目录
相关文章
|
安全 数据处理 开发工具
第三方SDK合规浅析
近日,工信部通报了22款APP、SDK存在侵害用户权益行为。通报超半数的原因违反了《个保法》最小化收集的原则,包括超范围收集个人信息,APP强制、频繁、过度索取权限。
335 1
‘you-get‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件
‘you-get‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件
518 0
|
JSON 数据格式
electron自定义最小化,最大化和关闭按钮
electron自定义最小化,最大化和关闭按钮
429 0
|
机器学习/深度学习 数据挖掘
R实战|从文献入手谈谈logistic回归、Cox回归以及Lasso分析(一)
R实战|从文献入手谈谈logistic回归、Cox回归以及Lasso分析(一)
1062 0
|
前端开发 应用服务中间件 nginx
使用Docker快速搭建Web服务器Nginx
本文指导如何使用Docker快速搭建Nginx服务器。首先,通过`docker pull`命令获取Nginx镜像,然后以容器形式运行Nginx并映射端口。通过挂载目录实现本地文件与容器共享,便于自定义网页。使用`docker ps`检查运行状态,访问IP:8088确认部署成功。最后,介绍了停止、删除Nginx容器的命令,强调Docker简化了服务器部署和管理。
|
前端开发 JavaScript
前端框架的选型、分类、常用框架整理(含官网链接)
前端框架的选型、分类、常用框架整理(含官网链接)
590 7
|
11月前
|
数据可视化 数据挖掘 UED
Plotly交互式数据可视化
【10月更文挑战第12天】本文介绍了如何使用 Plotly 实现交互式数据可视化,涵盖从安装 Plotly 到数据准备、图表创建、添加交互功能、导出图表及自定义图表样式的全过程。通过具体示例,展示了如何创建和优化交互式折线图,提升数据分析的效率和趣味性。
448 60
|
11月前
|
SQL 数据采集 数据可视化
深入 Python 数据分析:高级技术与实战应用
本文系统地介绍了Python在高级数据分析中的应用,涵盖数据读取、预处理、探索及可视化等关键环节,并详细展示了聚类分析、PCA、时间序列分析等高级技术。通过实际案例,帮助读者掌握解决复杂问题的方法,提升数据分析技能。使用pandas、matplotlib、seaborn及sklearn等库,提供了丰富的代码示例,便于实践操作。
267 64
|
9月前
|
Java Maven
Maven的生命周期
Maven生命周期分为清理、构建和站点生成三部分,每部分含多个固定顺序执行的阶段。清理包括pre-clean和clean;构建涵盖validate、compile、test、package、install及deploy;站点生成则有pre-site、site、post-site与site-deploy。
246 6
|
Kubernetes Java 容器
k8s部署springboot项目yaml
k8s部署springboot项目yaml
343 0