热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

单例模式深入浅出详细注释

1、单例模式1.1、单例设计模式它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建,这个类提供了一种访问其唯一的对象的方




1、单例模式

1.1、单例设计模式

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

数据库连接池就使用到了单例模式,初始化的时候创建譬如100个connection对象,然后再需要的时候
提供一个,用过之后返回到pool中,我们用单例模式,是保证连接池有且只有一个。不仅避免了实例的
重复创建,节约了内存,
使用线程池来管理线程,使用线程池来管理线程的好处是线程池中的线程可以复用,在一个线程使用过
时候,再返回到线程池中,不需要每次都创建一个线程。由于线程池是公共的,因此我们使用单例模式
来保证线程池有且仅有一个。

单例模式的优点:


  • 控制资源的使用,通过线程同步来控制资源的并发访问;
  • 控制实例产生的数量,达到节约资源的目的;
  • 作为通信媒介使用,也就是数据共享,它可以在不建立直接关联的条件下,让多个不相关的线程或者进程之间实现通信

    1.1.2、单例模式的实现

单例设计模式分两类:


  • 饿汉式:类加载就会导致该单例对象被创建
  • 懒汉式:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建

1、饿汉式----方式1(静态变量方式)

package com.njust.singleton.hungryman_staticvar;
/**
* @program: ruoyi
* @description:单例模式----饿汉式1-----静态成员变量法
* @author: tjj
* @create: 2021-09-24 18:55
**/
//类加载到内存后,就实例化一个单例,JVM保证线程安全
//缺点:无论是否用到,类加载时就完成实例化
public class SingletonStaticVar {
// 1.私有构造方法 --------- 为什么私有构造方法 ----> 当私有构造方法以后,外界就访问不到这个构造方法
private SingletonStaticVar() { }
//外界访问不到之后,就一个方法都创建不了------> 那如何实例化对象呢 -----> 自己在该类中创建一个该类的对象,供外界使用
// 2.在本类中创建该类对象, ------> 因为只能创建一次,所以用static修饰
private static SingletonStaticVar singletOnStaticVar= new SingletonStaticVar();
// 3.提供一个公共的访问方式,让外界去访问该对象------>getInstance是可以换名字的,不过是一个返回对象的方法----
// 不过最好用getInstance,业界都这样写
public static SingletonStaticVar getInstance(){
return singletonStaticVar;
}
/*
* 其他的业务方法,无所谓,随便加
* */
public void printM() {
System.out.println("M");
}
public void printQ() {
System.out.println("Q");
}

}

public class Client {
public static void main(String[] args) {
//创建singleton类的对象
SingletonStaticVar instance = SingletonStaticVar.getInstance();
System.out.println("创建的实例对象是:"+instance);
SingletonStaticVar instance2 = SingletonStaticVar.getInstance();
System.out.println("创建的实例对象2是:"+instance2);
//判断创建的两个对象是不是同一个对象 == 判断的是两个对象的 内存地址 是否一样
System.out.println(instance == instance2);
/*
* 然后就可以调用该类的方法了
* */
instance.printM();
instance2.printQ();
}
}

2.饿汉式----方式2-----(静态代码块)

public class SingletonStaticBlock {
//1.私有构造方法
private SingletonStaticBlock() {}
//2.声明SingletonStaticBlock类型的变量------>初始值为null
private static SingletonStaticBlock singletonStaticBlock;
//3.在静态代码块中赋值
static {
singletOnStaticBlock= new SingletonStaticBlock();
}
//4.对外提供一个获取该类对象的方法,自然也就是public
public static SingletonStaticBlock getInstance(){
return singletonStaticBlock;
}

/*
* 其他的业务方法,无所谓,随便加
* */
public void printM() {
System.out.println("M");
}
public void printQ() {
System.out.println("Q");
}
}

3.懒汉式

public class SingleLazyman {
//私有构造方法
private SingleLazyman() {}
//声明单例类型的变量---->只是声明了该类型的变量,并没有进行赋值--->null
private static SingleLazyman singleLazyman;
//对外提供访问方式 当多线程的时候,可能存在线程安全的问题
public static synchronized SingleLazyman getInstance() {
//懒汉式和饿汉式的区别--->懒汉式是首次使用该类的对象的时候,才会被创建---->为了只创建一次---->所以判断该类对象是否被创建了
//如果该类为null,那么便是第一次,创建(static很关键)
if( singleLazyman == null){
singleLazyman = new SingleLazyman();
return singleLazyman;
}
//如果已经创建了该类,那么便 不再创建,
return singleLazyman;
}
/*
* 该类的一些方法
* */
public void printM() {
System.out.println("M");
}
public void printA() {
System.out.println("A");
}
}

4.懒汉式-双重检查锁

讨论:懒汉模式加锁的问题

对于getInstance()方法来说,绝大部分的操作都是读操作,读操作是线程安全的,所以我们没有必要让每个线程必须持有锁才能调用该方法,我们需要调整加锁的时机========》由此产生了一种新的实现模式:双重检查锁!!!!!

package com.njust.singleton.lazyman_double_check_lock;
/**
* @program: ruoyi
* @description: 单例模式-----懒汉式-----双重检查锁方式
* @author: tjj
* @create: 2021-09-24 20:57
**/
//双重检查锁是一种很好的单例模式,解决了单例,性能,线程安全的问题
//存在问题:在多线程情况下,可能会出现空指针异常的问题--->原因:JVM在实例化对象的时候会进行优化和指令重排序操作
// ------->解决,使用volatile关键字!!!
public class SingleLazymanDoubleLock {
//私有构造方法
private SingleLazymanDoubleLock() {}
//声明该单例模式对象的变量
private static volatile SingleLazymanDoubleLock singleLazymanDoubleLock;
//对外提供公共的访问方式
public static SingleLazymanDoubleLock getInstance() {
//第一次判断,如果singleLazymanDoubleLock的值不为null,那么就不要抢占锁,直接返回对象
//如果为null,那么给它加一把锁
if (singleLazymanDoubleLock == null) {
synchronized (SingleLazymanDoubleLock.class) {
//第二次判断
if (singleLazymanDoubleLock == null) {
singleLazymanDoubleLock = new SingleLazymanDoubleLock();
}
}
}
return singleLazymanDoubleLock;
}
/*
* 该类的一些方法
* */
public void printR() {
System.out.println("R");
}
}

public class Client {
public static void main(String[] args) {
SingleLazymanSync instance = SingleLazymanSync.getInstance();
}
}

懒汉式-----静态内部类

// 静态内部类单例模式中,由内部类创建,由于 JVM在加载外部类的过程中,是不会加载静态内部类的, 只有静态内部类的属性/方法,被调用时才会被加载,
// 并初始化其静态属性. 静态属性由于被static修饰,保证只被实例化一次,并且严格保证实例化顺序.
//第一次加载SingletonLazymanInnerClass的时候不会初始化INSTANCE,只有第一次调用getInstance,虚拟机加载SingletonHolder并初始化
//INSTANCE,这样不仅能确保线程安全,也能保证SingletonLazymanInnerClass的唯一性
public class SingletonLazymanInnerClass {
//私有构造方法
private SingletonLazymanInnerClass() {}
//定义一个静态内部类
private static class SingletonHolder {
//在内部类中声明并初始化外部类的对象 为了防止外界对他进行修改---->加上final关键字
private static final SingletonLazymanInnerClass INSTANCE = new SingletonLazymanInnerClass();
}
//提供一个公共的访问方式
public static SingletonLazymanInnerClass getInstance() {
return SingletonHolder.INSTANCE;
}
/*
* 该类的一些方法,
* */
public void printL() {
System.out.println("L");
}
}

5.恶汉式-----枚举

枚举类实现单例模式是极力推荐的单例模式,因为枚举类型是线程安全的,并且只会装载一次,设计者充分利用了枚举的这个特性来实现单例模式

// 不考虑内存浪费空间的时候首选枚举类型
public enum SingletonEvilEnum {
INSTANCE;
}

public class Client {
public static void main(String[] args) {
SingletonEvilEnum instance = SingletonEvilEnum.INSTANCE;
SingletonEvilEnum instance2 = SingletonEvilEnum.INSTANCE;
System.out.println(instance == instance2);
//结果为true,可以看出枚举类的单例模式两次获取到的对象是同一个对象
}
}


推荐阅读
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • Oracle seg,V$TEMPSEG_USAGE与Oracle排序的关系及使用方法
    本文介绍了Oracle seg,V$TEMPSEG_USAGE与Oracle排序之间的关系,V$TEMPSEG_USAGE是V_$SORT_USAGE的同义词,通过查询dba_objects和dba_synonyms视图可以了解到它们的详细信息。同时,还探讨了V$TEMPSEG_USAGE的使用方法。 ... [详细]
  • 如何搭建Java开发环境并开发WinCE项目
    本文介绍了如何搭建Java开发环境并开发WinCE项目,包括搭建开发环境的步骤和获取SDK的几种方式。同时还解答了一些关于WinCE开发的常见问题。通过阅读本文,您将了解如何使用Java进行嵌入式开发,并能够顺利开发WinCE应用程序。 ... [详细]
  • OO第一单元自白:简单多项式导函数的设计与bug分析
    本文介绍了作者在学习OO的第一次作业中所遇到的问题及其解决方案。作者通过建立Multinomial和Monomial两个类来实现多项式和单项式,并通过append方法将单项式组合为多项式,并在此过程中合并同类项。作者还介绍了单项式和多项式的求导方法,并解释了如何利用正则表达式提取各个单项式并进行求导。同时,作者还对自己在输入合法性判断上的不足进行了bug分析,指出了自己在处理指数情况时出现的问题,并总结了被hack的原因。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 本文介绍了在iOS开发中使用UITextField实现字符限制的方法,包括利用代理方法和使用BNTextField-Limit库的实现策略。通过这些方法,开发者可以方便地限制UITextField的字符个数和输入规则。 ... [详细]
  • MPLS VP恩 后门链路shamlink实验及配置步骤
    本文介绍了MPLS VP恩 后门链路shamlink的实验步骤及配置过程,包括拓扑、CE1、PE1、P1、P2、PE2和CE2的配置。详细讲解了shamlink实验的目的和操作步骤,帮助读者理解和实践该技术。 ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • 本文介绍了在MFC下利用C++和MFC的特性动态创建窗口的方法,包括继承现有的MFC类并加以改造、插入工具栏和状态栏对象的声明等。同时还提到了窗口销毁的处理方法。本文详细介绍了实现方法并给出了相关注意事项。 ... [详细]
  • 本文介绍了RxJava在Android开发中的广泛应用以及其在事件总线(Event Bus)实现中的使用方法。RxJava是一种基于观察者模式的异步java库,可以提高开发效率、降低维护成本。通过RxJava,开发者可以实现事件的异步处理和链式操作。对于已经具备RxJava基础的开发者来说,本文将详细介绍如何利用RxJava实现事件总线,并提供了使用建议。 ... [详细]
author-avatar
小英
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有