Java单例模式的深入了解

Java单例模式的深入了解

单例模式是一种常用的设计模式,它确保一个类只有一个实例,同时提供一种全局访问的方式。

在Java中,单例模式有多种实现方式,我们既可以使用经典的饿汉式实现,也可以使用懒汉式、静态内部类等方式实现。本篇攻略将为大家深入讲解Java单例模式的各种实现方式及其优缺点,同时提供一些示例说明。

一、饿汉式单例模式

饿汉式单例模式是最简单的一种实现方式,它的核心思想是在类加载时创建实例对象,以确保全局只有一个实例。

饿汉式单例模式的实现方式如下:

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

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }
}

在以上代码中,我们将实例对象instance定义成static final类型,确保了全局只有一个实例。同时,构造函数被声明为private,避免了外部直接创建实例。

饿汉式单例模式的优点:

  • 实现简单,代码量少。
  • 线程安全,可以保证全局只有一个实例。

饿汉式单例模式的缺点:

  • 实例对象在类加载时被创建,如果该实例从未被使用,就会造成内存浪费。

二、懒汉式单例模式

懒汉式单例模式是另一种常用的实现方式,它的核心思想是在第一次使用时创建实例对象,以减少内存浪费。

懒汉式单例模式的实现方式如下:

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

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

在以上代码中,我们将实例对象instance初始化为null,只有在第一次调用getInstance()方法时才会创建实例对象。同时,getInstance()方法被声明为synchronized类型,确保线程安全。

懒汉式单例模式的优点:

  • 只有在需要时才会创建实例,可以避免内存浪费。
  • 线程安全,可以保证全局只有一个实例。

懒汉式单例模式的缺点:

  • 每次调用getInstance()方法都需要进行线程同步,可能会影响性能。
  • 由于是在第一次使用时才创建实例,因此如果多线程同时调用getInstance()方法,可能会创建多个实例。

三、静态内部类单例模式

静态内部类单例模式是一种较为优雅的实现方式,它的核心思想是在内部类中创建实例对象,以确保全局只有一个实例。

静态内部类单例模式的实现方式如下:

public class Singleton {
    private Singleton() {}

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

    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
}

在以上代码中,我们将实例对象instance放在内部静态类SingletonHolder中,当getInstance()方法被调用时,才会初始化SingletonHolder类,并创建唯一的实例对象。

静态内部类单例模式的优点:

  • 实现简单,线程安全。
  • 只有在需要时才会创建实例,可以避免内存浪费。

静态内部类单例模式的缺点:

  • 需要理解静态内部类的概念,阅读代码的过程中可能需要花费更多时间。

四、示例说明

1. 单线程环境下的示例

在单线程环境下,无论使用哪种实现方式,都可以保证全局只有一个实例:

Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();

assert(singleton1 == singleton2); // true

在以上代码中,我们通过两次调用getInstance()方法获取Singleton实例,然后通过assert()方法验证它们是否相等。

2. 多线程环境下的示例

在多线程环境下,饿汉式单例模式会产生多个实例的问题,懒汉式单例模式和静态内部类单例模式则可以通过加锁的方式保证线程安全:

// 懒汉式单例模式示例
ExecutorService executor = Executors.newFixedThreadPool(2);
List<Singleton> results = new ArrayList<>();
for (int i = 0; i < 100; i++) {
    executor.submit(() -> {
        Singleton singleton = Singleton.getInstance();
        results.add(singleton);
    });
}
executor.shutdown();
while (!executor.isTerminated());
assert(results.size() == 1);

// 静态内部类单例模式示例
ExecutorService executor = Executors.newFixedThreadPool(2);
List<Singleton> results = new ArrayList<>();
for (int i = 0; i < 100; i++) {
    executor.submit(() -> {
        Singleton singleton = Singleton.getInstance();
        results.add(singleton);
    });
}
executor.shutdown();
while (!executor.isTerminated());
Set<Singleton> set = new HashSet<>(results);
assert(results.size() == 1);
assert(set.size() == 1);

在以上代码中,我们通过线程池执行100个线程,每个线程都会调用getInstance()方法获取Singleton实例,并将它们添加到List或Set中。

由于饿汉式单例模式没有考虑多线程的情况,因此results列表可能会包含多个实例。而懒汉式单例模式和静态内部类单例模式使用了加锁的方式,确保了全局只有一个实例。其中,静态内部类单例模式需要验证List和Set中是否只有一个实例,因为存在单例被反序列化后出现多个实例的情况。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java单例模式的深入了解 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • 使用数据库客户端工具Oracle SQL Developer加载第三方驱动连接mysql的方法

    使用Oracle SQL Developer加载第三方驱动连接MySQL的方法: 下载并安装MySQL Connector/J JDBC驱动程序 要使用MySQL数据库连接Oracle SQL Developer,请下载并安装MySQL Connector/J JDBC 驱动程序。 在Oracle SQL Developer中设置MySQL驱动程序 在Ora…

    Java 2023年6月16日
    00
  • 浅谈在页面中获取到ModelAndView绑定的值方法

    获取ModelAndView中绑定的值是很常见的操作,在MVC框架中,ModelAndView作为控制器处理请求后返回给视图的结果,其包含有业务逻辑处理的结果、响应状态和视图(jsp、html等)等信息。下面是获取ModelAndView中绑定的值的几种方法: 方法一:使用EL表达式(${})获取 EL表达式是JavaEE提供的一种表达式语言,可以在JSP或…

    Java 2023年6月15日
    00
  • java实现希尔排序算法

    下面我就详细讲解一下“Java实现希尔排序算法”的攻略。 什么是希尔排序 希尔排序是插入排序的一种高效实现,也称为缩小增量排序。其基本思路是将待排序的元素分为若干组,对每组元素使用插入排序算法进行排序。然后逐渐减少元素分组的间隔,重复上述过程,直到元素之间间隔为1,获得最终的排序结果。 实现希尔排序的Java代码 下面是一个基于Java的希尔排序算法实现: …

    Java 2023年5月26日
    00
  • 读取spring配置文件的方法(spring读取资源文件)

    读取Spring配置文件是开发Spring应用程序的基本操作之一。以下是一些读取Spring配置文件的方法: 1. 使用 ClassPathXmlApplicationContext 通过 ClassPathXmlApplicationContext 读取 Spring 配置文件是最常见的方法之一。ClassPathXmlApplicationContext…

    Java 2023年5月20日
    00
  • SpringMvc响应数据及结果视图实现代码

    针对SpringMvc响应数据及结果视图实现代码的完整攻略,我们可以分为以下几个部分进行讲解。 一、SpringMVC响应数据的方式 SpringMVC提供了多种方式响应数据,分别如下: 转发 forward 重定向 redirect 返回JSON数据 返回XML数据 返回文件 1. 转发 forward 使用转发可以将请求转发给其他控制器或JSP页面。实现…

    Java 2023年6月15日
    00
  • 常见的Java字节码操纵库有哪些?

    常见的Java字节码操纵库 Java字节码操纵库是指一些工具类库,用于在运行时动态修改Java字节码。常见的Java字节码操纵库有以下几种: ASM:是一个直接以Java字节码的形式生成、修改类的框架。它提供了一些比较底层的API,可以让开发者精细地控制字节码的生成和修改过程。 Javassist:是一个基于字节码操作的程序库,可以在运行时对字节码进行修改、…

    Java 2023年5月11日
    00
  • Java对文件进行基本操作案例讲解

    当需要对文件进行基本操作时,Java提供了一系列的类和方法来实现对文件的读写和管理,这些类主要包括:File类、FileReader类、FileWriter类、BufferedReader类和BufferedWriter类等。下面将详细讲解如何在Java中对文件进行基本的操作。 创建文件 在Java中创建新的文件我们需要用到File类的createNewFi…

    Java 2023年5月20日
    00
  • Spark Streaming编程初级实践详解

    Spark Streaming编程初级实践详解 Spark Streaming是Apache Spark的一个扩展模块,它用于处理实时数据流。在本文中,我们将介绍Spark Streaming编程的基础知识和实践。主要包括以下内容: Spark Streaming简介 Spark Streaming编程基础 实时数据处理应用示例 Spark Streamin…

    Java 2023年6月2日
    00
合作推广
合作推广
分享本页
返回顶部