【设计模式】单例设计模式

简介: 1、前言单例模式是一种设计模式,它确保一个类只能创建一个实例,并提供一种全局访问这个实例的方式。在Java中,单例模式可以通过多种方式来实现,其中最常见的是使用私有构造函数和静态方法实现

1、前言

单例模式是一种设计模式,它确保一个类只能创建一个实例,并提供一种全局访问这个实例的方式。在Java中,单例模式可以通过多种方式来实现,其中最常见的是使用私有构造函数和静态方法实现

2、基本语法

在Java中,实现单例模式的方式有多种,其中最常见的实现方式包括以下几种:

2.1、懒汉式单例

懒汉式单例模式指的是在第一次使用单例对象时才创建实例。具体实现方式是在getInstance()方法中判断实例是否已经被创建,如果没有则创建一个新实例并返回。懒汉式单例模式的缺点是线程不安全,在多线程环境下可能会创建多个实例。

public class Singleton {
    private static Singleton instance;
    private Singleton() {
        // 私有构造函数
    }
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

2.2、饿汉式单例

饿汉式单例模式指的是在类加载时就创建实例,因此也被称为静态单例模式。具体实现方式是将实例化语句放在静态代码块中。由于在类加载时就创建了实例,因此不存在线程安全性问题。

public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton() {
        // 私有构造函数
    }
    public static Singleton getInstance() {
        return instance;
    }
}

2.3、双重检验锁单例模式

双重检验锁单例模式是一种线程安全的单例模式实现方式,它通过使用synchronized关键字来确保线程安全性。具体实现方式是在getInstance()方法中添加双重检验锁,这可以避免不必要的锁竞争和实例化。

public class Singleton {
    private static volatile Singleton instance;
    private Singleton() {
        // 私有构造函数
    }
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

2.4、静态内部类单例模式

静态内部类单例模式是一种比较常用的单例模式实现方式,它利用了静态内部类只会在被使用时才会加载的特点,从而避免了饿汉式单例模式的资源浪费和懒汉式单例模式的线程不安全问题。

public class Singleton {
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    private Singleton() {
        // 私有构造函数
    }
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

2.5、枚举单例模式

枚举单例模式是一种更为简单和安全的单例模式实现方式,它利用了Java中枚举类型本身就是单例的特点。枚举单例模式是一种天然线程安全的单例模式实现方式,而且可以防止反射和序列化等攻击。

public enum Singleton {
    INSTANCE;
    // 其他方法
}

2.6、ThreadLocal单例模式

ThreadLocal单例模式是一种可以在多线程环境下确保单例对象的线程安全单例模式实现方式。具体实现方式是在ThreadLocal中保存单例对象,每个线程都有自己的ThreadLocal副本,从而避免了线程安全性问题。

public class Singleton {
    private static final ThreadLocal<Singleton> INSTANCE = new ThreadLocal<Singleton>() {
        @Override
        protected Singleton initialValue() {
            return new Singleton();
        }
    };
    private Singleton() {
        // 私有构造函数
    }
    public static Singleton getInstance() {
        return INSTANCE.get();
    }
}

2.7、注册单例模式

注册式单例模式指的是通过一个注册表来管理所有单例对象,从而实现单例模式。具体实现方式是在一个静态的Map中保存所有单例对象,然后在需要使用单例对象时通过Map来获取。

public class Singleton {
    private static Map<String, Singleton> instances = new HashMap<>();
    private Singleton() {
        // 私有构造函数
    }
    public static Singleton getInstance(String name) {
        if (!instances.containsKey(name)) {
            instances.put(name, new Singleton());
        }
        return instances.get(name);
    }
}

3、使用场景

单例模式通常在需要确保全局只有一个实例的场景中使用,例如:

  1. 线程池:在多线程环境下,线程池需要保证只有一个实例。
  2. 数据库连接池:同样地,数据库连接池也需要保证只有一个实例。
  3. 日志对象:日志对象通常是全局可见的,因此需要保证只有一个实例。
  4. 配置文件:在某些情况下,需要全局共享的配置文件也需要保证只有一个实例。

4、使用示例

下面是一个简单的例子,演示如何使用单例模式实现线程池:

public class ThreadPool {
    private static ThreadPool instance;
    private ThreadPool() {
        // 初始化线程池
    }
    public static synchronized ThreadPool getInstance() {
        if (instance == null) {
            instance = new ThreadPool();
        }
        return instance;
    }
    // 线程池相关的方法
}

在上述代码中,我们使用synchronized关键字来保证getInstance()方法的线程安全性。这意味着每次只有一个线程可以访问getInstance()方法,从而避免了多个线程同时创建线程池实例的问题。

5、常见问题

单例模式的实现有一些常见问题,需要注意:

  1. 线程安全性:如上所述,如果多个线程同时访问getInstance()方法,可能会导致多个实例的创建。因此,需要确保getInstance()方法是线程安全的,可以通过synchronized关键字来实现。
  2. 序列化问题:如果单例类实现了Serializable接口,那么在反序列化时可能会创建多个实例。解决方法是在类中添加readResolve()方法,并返回单例实例。
  3. 反射问题:通过反射机制,可以调用私有构造函数创建实例。解决方法是在构造函数中添加判断,如果已经存在实例则抛出异常

6、总结

单例模式是一种非常常用的设计模式,在多线程环境下,它可以确保只有一个实例被创建,并提供一种全局访问这个实例的方式。在Java中,可以通过私有构造函数和静态方法实现单例模式。在实现单例模式时,需要注意线程安全性、序列化问题以及反射问题。尽管单例模式非常有用,但也有一些缺点,例如它可能导致代码变得更加复杂,而且在多线程环境下可能会影响性能。因此,在使用单例模式时需要根据具体情况进行权衡。

相关文章
|
6月前
|
设计模式
单例设计模式步骤
单例设计模式步骤
35 1
|
6月前
|
设计模式 安全 测试技术
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
142 0
|
6月前
|
设计模式 安全 Java
最简单的设计模式是单例?
单例模式可以说是Java中最简单的设计模式,但同时也是技术面试中频率极高的面试题。因为它不仅涉及到设计模式,还包括了关于线程安全、内存模型、类加载等机制。所以说它是最简单的吗?
80 3
最简单的设计模式是单例?
|
6月前
|
设计模式 安全 Java
【设计模式】2、设计模式分类和单例设计模式
【设计模式】2、设计模式分类和单例设计模式
58 0
|
6月前
|
设计模式 消息中间件 安全
多线程编程设计模式(单例,阻塞队列,定时器,线程池)(二)
多线程编程设计模式(单例,阻塞队列,定时器,线程池)(二)
60 1
|
6月前
|
设计模式 Java
26、Java 简单实现单例设计模式(饿汉式和懒汉式)
26、Java 简单实现单例设计模式(饿汉式和懒汉式)
56 2
|
6月前
|
设计模式 安全 Java
在Java中即指单例设计模式
在Java中即指单例设计模式
40 0
|
2月前
|
设计模式 存储 安全
设计模式——设计模式介绍和单例设计模式
饿汉式(静态常量)、饿汉式(静态代码块)、懒汉式(线程不安全)、懒汉式(线程安全,同步方法)、懒汉式(线程不安全,同步代码块)、双重检查(推荐,线程安全、懒加载)、静态内部类(推荐)、枚举(推荐)
设计模式——设计模式介绍和单例设计模式
|
3月前
|
设计模式 JavaScript 前端开发
从工厂到单例再到策略:Vue.js高效应用JavaScript设计模式
【8月更文挑战第30天】在现代Web开发中,结合使用JavaScript设计模式与框架如Vue.js能显著提升代码质量和项目的可维护性。本文探讨了常见JavaScript设计模式及其在Vue.js中的应用。通过具体示例介绍了工厂模式、单例模式和策略模式的应用场景及其实现方法。例如,工厂模式通过`NavFactory`根据用户角色动态创建不同的导航栏组件;单例模式则通过全局事件总线`eventBus`实现跨组件通信;策略模式用于处理不同的表单验证规则。这些设计模式的应用不仅提高了代码的复用性和灵活性,还增强了Vue应用的整体质量。
53 1
|
6月前
|
设计模式 安全 Java
【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式
【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式

热门文章

最新文章

  • 1
    C++一分钟之-设计模式:工厂模式与抽象工厂
    43
  • 2
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    49
  • 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
  • 下一篇
    无影云桌面