设计模式--单例模式

简介: 所谓类的单例模式 就是采取一定的方法保证在整个软件系统中对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法) 比如 Hibemate的SessionFactory 它充当数据存储源的代理 并负责创建Session对象 SessionFactory并不是轻量级的 一般情况下 一个 项目通常只需要一个SessionFactory就够 这样就需要用到单例模式了

介绍

所谓类的单例模式 就是采取一定的方法保证在整个软件系统中对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)


比如 Hibemate的SessionFactory 它充当数据存储源的代理 并负责创建Session对象 SessionFactory并不是轻量级的 一般情况下 一个 项目通常只需要一个SessionFactory就够 这样就需要用到单例模式了


单例模式的八种实现方式

饿汉式(静态常量)

public class HungryMan1 {

   //1 构造器私有话 外部不能直接new对象调用

   private HungryMan1(){}

   //2 本类内部创建对象实例

   private final static HungryMan1 instance = new HungryMan1();

   //3 提供一个公有的静态方法 返回实例对象

   public static HungryMan1 getInstance(){

       return instance;

   }

}

public class HungryManTest {

   public static void main(String[] args) {

       HungryMan1 instanbce = HungryMan1.getInstance();

       HungryMan1 instabce2 = HungryMan1.getInstance();

       System.out.println(instanbce == instabce2);

       System.out.println(instanbce.hashCode());

       System.out.println(instabce2.hashCode());

   }

}

测试结果

image.png



优缺点说明:

(1) 优点: 这种写法比较简单, 就是在类装载的时候就完成了实例化 避免了线程同步问题


(2) 缺点: 在类装载的时候就完车实例化 没有达到lazy loading(懒加载)的效果 如果从始至终从未使用过这个实例 则会造成内存浪费


(3) 这种方式基于classloader(类装载器)机制避免了线程同步问题 不过,instance在类装载时就实例化 在单例模式中大多数都是调用getInstance方法 但是导致类装载的原因有很多种 因此不能确定有其他的方式(或者其他的静态方法) 导致类装载 这时候初始化instance就没有达到lazy loading的效果


(4) 结论: 推荐使用,但是可能会造成内存浪费


在jdk   java.lang.Runtime#getRuntime()的源码中就是使用的饿汉式的单例模式


image.png


 


饿汉式(静态代码块)

public class HungryMan2 {

   private HungryMan2(){}

   //在静态代码块中 创建单例对象

   static {

       instance = new HungryMan2();

   }

   //2 本类内部创建对象实例

   private final static HungryMan2 instance;

   //3 提供一个公有的静态方法 返回实例对象

   public static HungryMan2 getInstance(){

       return instance;

   }

}

测试同 "饿汉式静态常量"一致


优缺点说明

(1) 这种方式和上面的方法类似 只不过将类实例化的过程放在了静态代码块中,也是在类装载的时候就执行了静态代码块中的代码 初始化类的实例 优缺点和上面是一样的


(2) 结论:推荐使用,但是可能造成内存浪费


懒汉式(线程不安全)

public class LazyMan1 {

   private static LazyMan1 instance;

   private LazyMan1(){};

   //提供一个静态的公有方法 当使用到该方法时 才会去创建 instance

   public static LazyMan1 getInstance(){

       if(instance==null){

           instance = new LazyMan1();

       }

       //等价于 jdk8 Optional写法

//        Optional.ofNullable(instance).orElseGet(()->new LazyMan1());

       return instance;

   }

}

测试同 "饿汉式静态常量"一致


优缺点说明

(1) 解决了lazy loading的问题 但是只能在单线程下使用 如果是多线程 可能会造成线程安全问题


(2) 如果再多线程下 一个线程进入了 if(instance==null)的判断语句块 还没来的及往下执行 另一个线程也通过了这个判断语句,此时就会产生多个实例 所以在多线程环境下不可以使用这种方式


(3) 结论: 在实际开发中 不要使用这种方式


懒汉式(线程安全 同步方法)

public class LazyMan2 {

   private static LazyMan2 instance;

   private LazyMan2(){};

   //提供一个静态的公有方法 加入同步处理的代码 解决线程安全问题

   public static synchronized LazyMan2 getInstance(){

       if(instance==null){

           instance = new LazyMan2();

       }

       return instance;

   }

}

测试同 "饿汉式静态常量"一致


优缺点说明

(1) 解决了线程不安全问题


(2) 效率低 每个 线程在想获得类的实例的时候 执行getInstance()方法都要进行同步 而其实这个方法只需要执行一次实例化代码就可以了 后面的想获得该类实例 直接return就可以了 方法进行同步效率太低


(3) 结论: 在实际开发中 不推荐使用


懒汉式(线程安全 同步代码块)

public class LazyMan3 {

   private static LazyMan3 instance;

   private LazyMan3(){};

   //提供一个静态的公有方法 加入同步处理的代码 解决线程安全问题

   public static LazyMan3 getInstance(){

       if(instance==null){

           synchronized(LazyMan3.class){

               instance = new LazyMan3();

           }

       }

       return instance;

   }

}

测试同 "饿汉式静态常量"一致


优缺点说明

(1) 这种方式 本意是想对 懒汉式(线程安全 同步方法)的改进,因为同步方法效率太低 改为同步产生实例化的代码块


(2) 但是这种同步不能起到线程同步的作用 跟 懒汉式(线程不安全) 遇到的情形一致 假如一个线程进入了 if(instance==null) 判断语句块 还没来得及往下执行 另一个线程也通过了这个判断语句 这时便会产生多个实例


(3) 结论: 在实际开发中 不要用这种方式


双重检查

public class LazyMan4 {

   private static volatile LazyMan4 instance;

   private LazyMan4(){};

   //提供一个静态的公有方法 加入双重检查代码 解决线程安全问题 同时解决懒加载问题

   public static synchronized LazyMan4 getInstance(){

       if(instance==null){

           synchronized(LazyMan4.class){

               if(instance==null){

                   instance = new LazyMan4();

               }

           }

       }

       return instance;

   }

}

测试同 "饿汉式静态常量"一致


优缺点说明

(1) double-check 概念是多线程开发中常使用到的 如代码中所示进行了两次 if(instance==null)检查 这样就可以保证线程安全了


(2) 这样 实例化代码只用执行一次 后面再次访问时 判断 if(instance==null),直接return实例化对象 也避免的反复进行方法同步


(3) 线程安全 延迟加载 效率较高


(4) 结论: 在实际开发中 推荐使用


静态内部类

public class LazyMan5 {

   private LazyMan5(){};

   //书写静态内部类 该类中有一个静态属性 LazyManInstance

   private static class LasyManInstance{

       private static final LazyMan5 INSTANCE = new LazyMan5();

   }

   //提供一个静态公有方法 直接返回LazyManInstance.INSTANCE

   public static synchronized LazyMan5 getInstance(){

       return LasyManInstance.INSTANCE;

   }

}

测试同 "饿汉式静态常量"一致


优缺点说明

(1) 这种方式采用了类装载的机制来保证初始化实例时只有一个线程


(2) 静态内部类方式在LazyMan5类被装载时并不会立即实例化 而是在需要实例时 调用 getInstance方法 才会装载LazyManInstance类 从而完成LazyMan5的实例化


(3) 类的静态属性只会在第一次加载类的时候初始化 所以在这里 是jvm帮我们保证了线程的安全性 在类进行初始化时 别的线程是无法进入的


(4) 解决了线程安全问题 利用静态内部类特点实现延迟加载 效率高


(5)结论: 推荐使用


枚举

public class HungryManTest {

   public static void main(String[] args) {

       LazyMan6 in = LazyMan6.INSTANCE;

       LazyMan6 in2 = LazyMan6.INSTANCE;

       in.sayHello();

       System.out.println(in==in2);

   }

}

enum LazyMan6 {

   INSTANCE;

   public void sayHello(){

       System.out.println("hello world!");

   }

}

测试:


image.png


优缺点说明:

(1) 借助jdk1.5中添加的枚举来实现单例模式 不仅能避免多线程同步问题 而且还能防止反序列化重新创建新的对象


(2) 这种方式是Effective java作者Josh Bloch推荐的方式


(3)结论:推荐使用


单例模式的注意事项和细节说明

(1) 单例模式保证了系统内存中该类只存在一个对象 节省了系统资源 对于一些需要频繁创建销毁的对象 使用单例模式可以提高系统性能


(2) 当想实例化一个单例类的时候 必须要记住使用响应的获取对象的方法 而不是使用new


(3) 单例模式使用的场景: 需要频繁的进行创建和销毁的对象 创建对象时耗时过多或耗费资源过多(重量级对象) 但又经常用到的对象 工具类对象 频繁访问数据库文件的对象(比如数据源 session工厂等)

相关文章
|
1月前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
29 2
|
6天前
|
设计模式 Java 数据库连接
Java编程中的设计模式:单例模式的深度剖析
【10月更文挑战第41天】本文深入探讨了Java中广泛使用的单例设计模式,旨在通过简明扼要的语言和实际示例,帮助读者理解其核心原理和应用。文章将介绍单例模式的重要性、实现方式以及在实际应用中如何优雅地处理多线程问题。
19 4
|
15天前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
|
23天前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入理解与应用
【10月更文挑战第22天】 在软件开发中,设计模式是解决特定问题的通用解决方案。本文将通过通俗易懂的语言和实例,深入探讨PHP中单例模式的概念、实现方法及其在实际开发中的应用,帮助读者更好地理解和运用这一重要的设计模式。
16 1
|
6天前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
16 0
|
1月前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入解析与实践
在PHP开发中,设计模式是提高代码可维护性、扩展性和复用性的关键技术之一。本文将通过探讨单例模式,一种最常用的设计模式,来揭示其在PHP中的应用及优势。单例模式确保一个类仅有一个实例,并提供一个全局访问点。通过实际案例,我们将展示如何在PHP项目中有效实现单例模式,以及如何利用这一模式优化资源配置和管理。无论是PHP初学者还是经验丰富的开发者,都能从本文中获得有价值的见解和技巧,进而提升自己的编程实践。
|
1月前
|
设计模式 安全 Java
C# 一分钟浅谈:设计模式之单例模式
【10月更文挑战第9天】单例模式是软件开发中最常用的设计模式之一,旨在确保一个类只有一个实例,并提供一个全局访问点。本文介绍了单例模式的基本概念、实现方式(包括饿汉式、懒汉式和使用 `Lazy<T>` 的方法)、常见问题(如多线程和序列化问题)及其解决方案,并通过代码示例详细说明了这些内容。希望本文能帮助你在实际开发中更好地应用单例模式,提高代码质量和可维护性。
31 1
|
1月前
|
设计模式 缓存 数据库连接
探索PHP中的设计模式:单例模式的实现与应用
在PHP开发中,设计模式是提高代码可复用性、可维护性和扩展性的重要工具。本文将深入探讨单例模式(Singleton Pattern)的基本概念、在PHP中的实现方式以及实际应用场景。单例模式确保一个类仅有一个实例,并提供全局访问点。通过具体代码示例和详细解释,我们将展示如何在PHP项目中有效利用单例模式来解决实际问题,提升开发效率和应用性能。
|
1月前
|
设计模式 存储 测试技术
PHP中的设计模式:单例模式的深入解析与实践
在PHP开发领域,设计模式是解决常见问题的最佳实践。本文将深入探讨单例模式,一种确保类只有一个实例的设计模式,并提供实际应用示例。我们将从单例模式的基本概念讲起,通过实际案例展示如何在PHP中实现单例模式,以及它在不同场景下的应用和优势。最后,我们会探讨单例模式的优缺点,帮助开发者在实际项目中做出明智的选择。
|
1月前
|
设计模式 SQL 安全
PHP中的设计模式:单例模式的深入探索与实践在PHP开发领域,设计模式是解决常见问题的高效方案集合。它们不是具体的代码,而是一种编码和设计经验的总结。单例模式作为设计模式中的一种,确保了一个类仅有一个实例,并提供一个全局访问点。本文将深入探讨单例模式的基本概念、实现方式及其在PHP中的应用。
单例模式在PHP中的应用广泛,尤其在处理数据库连接、日志记录等场景时,能显著提高资源利用率和执行效率。本文从单例模式的定义出发,详细解释了其在PHP中的不同实现方法,并探讨了使用单例模式的优势与注意事项。通过对示例代码的分析,读者将能够理解如何在PHP项目中有效应用单例模式。

热门文章

最新文章

  • 1
    C++一分钟之-设计模式:工厂模式与抽象工厂
    43
  • 2
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    50
  • 3
    C++一分钟之-C++中的设计模式:单例模式
    58
  • 4
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    38
  • 5
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    63
  • 6
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    58
  • 7
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    42
  • 8
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    50
  • 9
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    110
  • 10
    Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
    78
  • 下一篇
    无影云桌面