设计模式(1)单例模式

简介: 单例模式是一种常见的设计模式,写法也比较多,在这篇文章里面主要是对单例模式的各种写法进行一个介绍。这篇文章的主要内容如下:首先简单的介绍一下单例模式的使用场景然后就是单例模式写法的介绍。最后对单例模式进行一个总结

一、单例模式的介绍


比较官方的理解:

单例模式确保某个类只有一个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。

有一个通俗的理解,那就是在古代,全国就一个皇帝。如何确保一个皇帝?这就是单例模式。


二、单例模式的各种写法


1、懒汉式:基本写法


public class Singleton {
    private Singleton() {}//构造方法
    private static Singleton single=null; 
    public static Singleton getInstance() { 
         if (single == null) {  
             single = new Singleton();
         }  
        return single;
    }
}

特点:


  • 线程不安全(并发时可能出现多个单例)
  • 构造方法为private,限定了外部只能从getInstance去获取单例
  • 使用static关键字,表明全局只有一份节约了资源,但第一次加载在getInstance()需要实例化,需要一定时间。


2、懒汉式:使用synchronized 同步


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


特点:

  • 线程安全
  • 效率太低(synchronized)
  • 耗内存


3、懒汉式:双重检查锁定


public class Singleton{
    private static Singleton instance;  
    private Singleton (){} 
    public static Singleton getInstance() {
        //第一次检查
        if (singleton == null) {  
          synchronized (Singleton.class) { 
              //第二次检查
             if (singleton == null) {  
                singleton = new Singleton(); 
             }  
          }  
       }  
       return singleton; 
    }
}


特点:

  • 线程安全
  • 比较常用,但是synchronized依然有一定的性能影响


4、饿汉式:基本写法(instance为private)


public class Singleton {
    private Singleton() {}
    //提前创建一个Singleton
    private static final Singleton instance = new Singleton();
    //有调用者直接就拿出来给了
    public static Singleton getInstance() {
        return instance;
    }
}


特点:

  • 线程安全(因为提前创建了,所以是天生的线程安全)
  • instance在类加载时就实例化


5、饿汉式:基本写法(instance为public)


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


特点:

  • 简单
  • 带来一定的效率问题


6、饿汉式:静态代码块


public class Singleton {
    private Singleton instance = null;
    private Singleton() {}
    // 初始化顺序:基静态、子静态 -> 基实例代码块、基构造 -> 子实例代码块、子构造
    static {
        instance = new Singleton(); 
    }
    public static Singleton getInstance() {
        return this.instance;
    }
}


特点:

  • 线程安全
  • 类初始化时实例化 instance


7、静态内部类


public class Singleton {  
    //静态内部类里面创建了一个Singleton单例
    private static class InstanceHolder  {  
       private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
       return InstanceHolder.INSTANCE;  
    }  
}


特点:

  • 线程安全
  • 效率高,避免了synchronized带来的性能影响


8、枚举式


public enum Singleton {
    INSTANCE;
    // 枚举同普通类一样,可以有自己的成员变量和方法
    public void getInstance() {
        System.out.println("Do whatever you want");
    }
}


特点:

  • 线程安全(枚举类型默认就是安全的)
  • 避免反序列化破坏单例


9、CAS方式


public class Singleton {
    // AtomicReference 是原子引用类型
    private static final AtomicReference<Singleton> INSTANCE 
        = new AtomicReference<Singleton> ();
    private Singleton() {}
    public static Singleton getInstance() {
        for(;;) {
            Singleton instance = INSTANCE.get();
            if(instance != null) {
                return instance;
            }
            instance = new Singleton();
            // CAS 方法有两个参数 expect 和 update,以原子方式实现了比较并设置的功能
            // 如果当前值等于 expect,则更新为 update 并返回 true;否则不更新并返回 false
            if(INSTANCE.compareAndSet(null, instance)) {
                return instance;
            }
        }
    }
}


特点:

  • 优点:不需要使用传统的锁机制来保证线程安全,CAS 是一种基于忙等待的算法,依赖底层硬件的实现,相对于锁它没有线程切换和阻塞的额外消耗,可以支持较大的并行度。
  • 缺点:如果忙等待一直执行不成功(一直在死循环中),会对 CPU 造成较大的执行开销。而且,这种写法如果有多个线程同时执行 singleton = new Singleton(); 也会比较耗费堆内存。


10、Lock机制


// 类似双重校验锁写法
public class Singleton {
       private static Singleton instance = null;
       private static Lock lock = new ReentrantLock();
       private Singleton() {}
       public static Singleton getInstance() {
           if(instance == null) {
               lock.lock(); // 显式调用,手动加锁
               if(instance == null) {
                   instance = new Singleton();
               }
               lock.unlock(); // 显式调用,手动解锁
           }
           return  instance;
       }
}


当然还有一些其他的实现单例的写法,比如说登记式单例等等。


三、总结


v2-31afad5723314dbfce0adb8f908b1388_1440w.jpg

有两种场景可能导致非单例的情况


  • 场景一:如果单例由不同的类加载器加载,那便有可能存在多个单例类的实例
  • 场景二:如果 Singleton 实现了 java.io.Serializable 接口,那么这个类的实例就可能被序列化和反序列化。


单例的写法基本上就是这些,可能在不同的场景下使用不同的方式,对我来说,在后端更经常使用的就是枚举类型,但是Android开发当中很少使用。

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