前言

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

饿汉单例

是否多线程安全:是

是否懒加载:否

正如名字含义,饿汉需要直接创建实例。

public class EhSingleton {
    private static EhSingleton ehSingleton = new EhSingleton();
    private EhSingleton() {}
    public static EhSingleton getInstance(){
        return ehSingleton;
    }
}

缺点: 类加载就初始化,浪费内存

优点: 没有加锁,执行效率高。还是线程安全的实例。

懒汉单例

懒汉单例,在类初始化不会创建实例,只有被调用时才会创建实例。

非线程安全的懒汉单例

是否多线程安全:否

是否懒加载: 是

public class LazySingleton {
    private static LazySingleton ehSingleton;
    private LazySingleton() {}
    public static LazySingleton getInstance() {
        if (ehSingleton == null) {
            ehSingleton = new LazySingleton();
        }
        return ehSingleton;
    }
}

实例在调用 getInstance 才会创建实例,这样的优点是不占内存,在单线程模式下,是安全的。但是多线程模式下,多个线程同时执行 if (ehSingleton == null) 结果都为 true,会创建多个实例,所以上面的懒汉单例是一个线程不安全的实例。

加同步锁的懒汉单例

是否多线程安全:是

是否懒加载: 是

为了解决多个线程同时执行 if (ehSingleton == null) 的问题,getInstance 方法添加同步锁,这样就保证了一个线程进入了 getInstance 方法,别的线程就无法进入该方法,只有执行完毕之后,其他线程才能进入该方法,同一时间只有一个线程才能进入该方法。

public class LazySingletonSync {
    private static LazySingletonSync lazySingletonSync;
    private LazySingletonSync() {}
    public static synchronized LazySingletonSync getInstance() {
        if (lazySingletonSync == null) {
            lazySingletonSync =new LazySingletonSync();
        }
        return lazySingletonSync;
    }
}

这样配置虽然保证了线程的安全性,但是效率低,只有在第一次调用初始化之后,才需要同步,初始化之后都不需要进行同步。锁的粒度太大,影响了程序的执行效率。

双重检验懒汉单例

是否多线程安全:是

是否懒加载:是

使用 synchronized 声明的方法,在多个线程访问,比如A线程访问时,其他线程必须等待A线程执行完毕之后才能访问,大大的降低的程序的运行效率。这个时候使用 synchronized 代码块优化执行时间,减少锁的粒度

双重检验首先判断实例是否为空,然后使用 synchronized (LazySingletonDoubleCheck.class) 使用类锁,锁住整个类,执行完代码块的代码之后,新建了实例,其他代码都不走 if (lazySingletonDoubleCheck == null) 里面,只会在最开始的时候效率变慢。而 synchronized 里面还需要判断是因为可能同时有多个线程都执行到 synchronized (LazySingletonDoubleCheck.class) ,如果有一个线程线程新建实例,其他线程就能获取到 lazySingletonDoubleCheck 不为空,就不会再创建实例了。

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

静态内部类

是否多线程安全:是

是否懒加载:是

外部类加载时,并不会加载内部类,也就不会执行 new SingletonHolder(),这属于懒加载。只有第一次调用 getInstance() 方法时才会加载 SingletonHolder 类。而静态内部类是线程安全的。

静态内部类为什么是线程安全

静态内部类利用了类加载机制的初始化阶段 方法,静态内部类的静态变量赋值操作,实际就是一个 方法,当执行 getInstance() 方法时,虚拟机才会加载 SingletonHolder 静态内部类,

然后在加载静态内部类,该内部类有静态变量,JVM会改内部生成方法,然后在初始化执行方法 —— 即执行静态变量的赋值动作。

虚拟机会保证 方法在多线程环境下使用加锁同步,只会执行一次 方法。

这种方式不仅实现延迟加载,也保障线程安全。

public class StaticClass {
    private StaticClass() {}
    private static class SingletonHolder {
        private static final SingletonHolder INSTANCE = new SingletonHolder();
    }

    public static final SingletonHolder getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

总结

  • 饿汉单例类加载就初始化,在没有加锁的情况下实现了线程安全,执行效率高。但是无论有没有调用实例都会被创建,比较浪费内存。
  • 为了解决内存的浪费,使用了懒汉单例,但是懒汉单例在多线程下会引发线程不安全的问题。
  • 不安全的懒汉单例,使用 synchronized 声明同步方法,获取实例就是安全了。
  • synchronized 声明方法每次线程调用方法,其它线程只能等待,降低了程序的运行效率。
  • 为了减少锁的粒度,使用 synchronized 代码块,因为只有少量的线程获取实例,实例是null,创建实例之后,后续的线程都能获取到线程,也就无需使用锁了。可能多个线程执行到 synchronized ,所以同步代码块还需要再次判断一次。
  • 静态内部类赋值实际是调用 方法,而虚拟机保证 方法使用锁,保证线程安全。

到此这篇关于Java单例模式的五种实现方式的文章就介绍到这了,更多相关Java单例模式内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

Java单例模式的五种实现方式的更多相关文章

  1. Swift 单例模式实现及类方法

    在开始单例模式之前我们先讲一下类方法。应为单例模式需要依靠类方法来实现首先,我们知道类方法就是直接使用类名来调用,无需生成对象,再去调用。比如我们属性的NSUserdefault就是一个单例接下来我们实现一个类,用来共享数据。

  2. Swift多种实现单例写法

    学习Swift的单例写法,以下提供了5种方式,一起来看看吧!

  3. Swift中单例的集中创建方式

    单例模式是设计模式中最简单的一种,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象。下面看看swift中创建单例的集中方式:1、一个句话搞定,所有用到的地方都是同一个2、3、4.swift还在初学阶段,如果有不对的地方,还望指出。

  4. Swift百万线程攻破单例Singleton)模式

    回到技术问题,我们想要更多的线程访问SwiftSingleton.shared方法,只要先准备好所有的线程,然后发一个信号,让他们同时去访问这个方法就可以了。测试结果:通过2、使用GCD技术实现的单例模式dispatch_once{Inner.instance=SwiftSingleton()}returnInner.instance!

  5. Swift中的单例模式

    三种方法实现单例模式,线程安全1.全局变量2.结构3.dispatch_once1.全局变量:这里使用了全局变量而非类变量,是因为不支持类变量2.结构:与类不同,结构可以定义静态变量,通过使用此方法,将静态变量升级为类变量3.dispatch_once:

  6. 《从零开始学Swift》学习笔记Day 63――Cocoa Touch设计模式及应用之单例模式

    实际上,除了软件设计,设计模式也被广泛应用于其他领域,比如UI设计和建筑设计等。下面来介绍CocoaTouch框架中的设计模式中的单例模式。单例模式单例模式的作用是解决“应用中只有一个实例”的一类问题。在CocoaTouch框架中,有UIApplication、NSUserDefaults和NSNotificationCenter等单例类。另外,NSFileManager和NSBundle类虽然属于Cocoa框架的内容,但也可以在CocoaTouch框架中使用。解决方案单例模式的实现有很多方案,苹果公司在

  7. Swift设计模式之单例模式

    转自Swift设计模式原文Design-Patterns-In-Swift

  8. swift基础之实现单例模式(仿NSUserDefaults)

    单例模式是设计模式中最简单的一种,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象。下面看看swift中的几种实现方式:1、一句话搞定,静态常理。所有地方用到的都是同一个2、使用dispatch_once可以保证其中的代码只执行一次3、4、在方法内定义静态常量下面为NSUserdefaults的运用

  9. Swift3 单例模式

    常见的有这么几种方法第一种最简单也是最常用的,这里的所有单例init方法一定要定义成private的,不然外部依然可以使用init方法初始化变量。final关键字的作用是这个类或方法不希望被继承和重写第二种第二种完全是OC风格的单例,但是由于Swift3中废弃了原来的dispatch_once_t,所以需要先给dispatchQueue添加一个extension,实现原先的dispatch_once_t效果第三种第四种在方法内定义静态变量

  10. Swift 1.2中的单例模式

    我之前使用过以下单例模式:当使用Swift1.2发布新的Xcodebeta时,我想尝试新的静态类属性和方法.所以我尝试了类似的东西:在使用它时查看调试器,似乎很多单例类的嵌套实例是由类常量创建的:但是通过分配来看,似乎只创建了一个实例.我想这意味着它正常工作,但我没有看到第一个模式的相同行为.这里发生的事情是LLDB向您显示静态数据,就好像它是实例数据一样.因为它是静态数据,所以它不像正常实例数据

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部