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. 以静态方法或者枚举返回实例
  3. 确保实例只有一个,尤其在多线程环境下
  4. 确保反序列化不会创建新的实例

常用单例模式构造方法

  • 饿汉
  • 懒汉
  • 双重锁懒汉
  • 静态内部类
  • 枚举

饿汉模式

public class SingletonTest {
    private static SingletonTest INSTANCE = new SingletonTest();
    private SingletonTest() {}
    public static SingletonTest getInstance(){
        return INSTANCE;
    }
}

饿汉模式在类初始化时就在内存中创建对象,以空间换时间,不存在线程安全问题。

懒汉模式

public class SingletonTest2 {
    private static SingletonTest2 INSTANCE = null;
    private SingletonTest2(){}
    private static SingletonTest2 getInstance(){
        return new SingletonTest2();
    }
}

饿汉模式在静态方法被调用时创建实例,已时间换空间,存在线程安全问题。当然在多线程环境下,实现一个大型的实例单例化时存在风险,故我们接下来将讨论如何使得懒汉模式在多线程条件下使用。

双重锁懒汉模式(Double Check Lock)

public class SingletonTest3 {
    private static SingletonTest3 INSTANCE = null;
    private SingletonTest3(){}
    private static SingletonTest3 getInstance(){
        if(INSTANCE == null){
            synchronized (SingletonTest3.class){
                if(INSTANCE == null){
                    INSTANCE = new SingletonTest3();
                }
            }
        }
        return INSTANCE;
    }
}

DCL模式无疑是解决懒汉模式线程安全问题的方法之一,DCL的优点是只有在对象初始化时被创建,首次判断实例为空是为了避免盲目加锁,当第一次加载方法时,对实例进行加锁和实例化,既节省了时间也节省了空间,但由于JVM存在乱序执行的优化策略,往往使得DCL也存在线程不安全问题

举个荔枝

INSTANCE = new SingletonTest3();

这句话在执行时其实JVM分为三步 去创建对象

  1. 堆内存开辟内存空间
  2. 实例化类方法,变量
  3. 将对象指针指向推内存地址

但是在2未执行完成时,jvm有可能先执行3步骤,使得新线程来时,对象实例不为空将实例返回,使得对象存在问题DCL存在不安全

解决方法

在jdk1.5之后官方具体化了volatile 使用关键字修饰既可保证DCL安全问题

private volatile static SingleTon INSTANCE = null;

静态内部类模式

public class SingletonTest4 {
    private SingletonTest4(){}

    private static class SingletonInstance{
        private static SingletonTest4 INSTANCE = new SingletonTest4();
    }
    public static SingletonTest4 getInstance(){
        return SingletonInstance.INSTANCE;
    }
}

静态内部类的形式既可以使得空间节省,也可以使得内存节省,外部类加载时并不需要直接加载内部类,而是在访问静态方法时才去加载内部类。

那么静态内部类如何保证线程安全性呢?首先了解类的加载机制。

  1. 遇到new ,getstatic,setstatic,invokestatic字节码指令时类加载。
  2. 使用反射机制java.lang.reflect
  3. 实例化子类时,加载父类
  4. 当方法遇到java.lang.invoke.MethodHandle 句柄时,为初始化,就会执行初始化操作。

当类对象执行静态方法获取实例对象时,会执行实例化静态内部类 使得实例方法只被new 一次而不会多次去创建 避免多线程情况下不安全的情况。当getInstance()方法被调用时,SingletonInstance才在SingleTon4的运行时常量池里,把符号引用替换为直接引用,这时静态对象INSTANCE也真正被创建,然后再被getInstance()方法返回出去,这点同饿汉模式。jvm在实例化类时会调用方法,在类对象实例化时,jvm会保证对象加锁,同步保证同一时间只有一个线程调用方法,其他线程进行实例化是阻塞线程,保证线程安全性。

枚举方式

public enum SingleTonEnum {
    INSTANCE;
    SingleTonEnum() {
        instance = new Resource();
    }
    private Resource instance;
    public Resource getInstance() {
        return instance;
    }
}
class Resource{
    
}

在java中枚举可以有自己的方法和属性,枚举也是绝对线程安全的,任何情况下都是一个单例。

SingleTonEnum.INSTANCE;
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-21 15:13:47  更:2021-08-21 15:14:27 
 
开发: 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年5日历 -2024/5/21 4:21:49-

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