IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 设计模式之单例模式 -> 正文阅读

[Java知识库]设计模式之单例模式

定义与介绍

指一个类只有一个实例,且该类能自行创建这个实例的一种模式。

使用场景: 某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。

优点:

  1. 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。

  2. 避免对资源的多重占用(比如写文件操作)。

缺点:

  1. 单例模式的功能代码通常写在一个类中,如果功能设计不合理,扩展困难。

单理模式的实现

1. 懒汉式,线程不安全

使用了懒加载的设计,即只在需要调用是才进行初始化,但是不能保证线程并发安全。

public class Singleton {
    private static Singleton instance;
    private Singleton (){}

    public static Singleton getInstance() {
     if (instance == null) {
         instance = new Singleton();
     }
     return instance;
    }
}

2. 懒汉式,线程安全

为了解决线程安全问题,直接对整个方法加锁。

但只会在第一次调用时进行初始化,这要书写会导致后续每次都只能有一个线程进行调用,效率不高。

public class Singleton {
    private static Singleton instance;
    private Singleton (){}

    public static synchronized Singleton getInstance() {
     if (instance == null) {
         instance = new Singleton();
     }
     return instance;
    }
}

3. 懒汉式,双重校验锁

不对整个方法上锁,只在进行初始化时,对代码块进行上锁。

问:为什么有两次校验?

答:可能有多个线程同时进入第一个if 校验,防止重复初始化。

问:为什么加 volatile ?

答:因为 instance = new Singleton(); 这句代码并不是原子性操作,在 JVM 中大概有以下操作:

  1. 给 instance 分配内存。
  2. 调用 Singleton 的构造函数来初始化成员变量。
  3. 将instance对象指向分配的内存空间(执行完这步 instance 就为非 null 了)。

但是 JVM 并不一定按照 1-2-3 来的,也可能是 1-3-2

如果是第二种,当执行到 3 时,下一个线程进来,检验到的 instance 不为空,则返回进行调用,就会出现报错的情况。

public class Singleton {
    private volatile static Singleton instance;
    private Singleton (){}

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

4. 饿汉式

类一旦加载就创建一个单例,没有加锁,执行效率提高,但是缺点也很明显,如果这个类没有被调用会浪费一定的内存空间。

且有些类是需要根据配置文件加载,或根据不同参数进行设置的,在这种情况下饿汉式写法就无法满足需求。

public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton (){}

    public static Singleton getInstance() {
     	return instance;
    }
}

5. 静态嵌套类

这种写法的原理是:当 JVM 加载一个类时,不会去加载这个类的嵌套类。

只有当我们去调用 getInstance() 时, JVM 才会去初始化 SingletonHolder

静态属性保证了全局唯一,静态变量初始化保证了线程安全,所以这里的方法没有加 synchronized 关键字( JVM保证了一个类的 初始化在多线程下被同步加锁 )。

public class Singleton {  
    private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE; 
    }  
}

6. 枚举

创建枚举默认就是线程安全的,所以不需要加锁。这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。

public enum Singleton{
    INSTANCE;
}

总结

一般情况下直接使用饿汉式就好了,如果明确要求要懒加载(lazy loading )会倾向于使用静态内部类,如果涉及到反序列化创建对象时会试着使用枚举的方式来实现单例。如果有其他特殊的需求,可以考虑使用双重校验锁的方式。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-11 21:59:56  更:2022-03-11 22:02:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:31:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码