Java单例模式的6种实现方式详解

Java单例模式的6种实现方式详解

前言

单例模式是一种常见的设计模式,它可以保证一个类只有一个实例,并为外界提供唯一的访问入口。在实际开发中,单例模式经常被用于创建一些共享资源的场景,如数据库连接池、线程池等。本文将详细介绍Java中单例模式的六种实现方式。

1. 饿汉式(静态常量)

饿汉式单例模式的实现方式非常简单,就是在类加载的时候立即创建单例对象,因此也被称为静态常量方式。

public class Singleton {
    private static final Singleton INSTANCE = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

使用场景:适用于单例对象较小,没有过多的资源占用的情况下。

示例:

public class Main {
    public static void main(String[] args) {
        Singleton instance1 = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance1 == instance2); // 输出 true
    }
}

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

饿汉式单例模式的一种变种是静态代码块方式,它与静态常量方式的区别在于在静态代码块中可以进行一些初始化操作。

public class Singleton {
    private static final Singleton INSTANCE;
    static {
        INSTANCE = new Singleton();
        // 在这里进行初始化操作
    }
    private Singleton() {}
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

使用场景:适用于单例对象需要进行一些初始化操作的情况下。

示例:

public class Main {
    public static void main(String[] args) {
        Singleton instance1 = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance1 == instance2); // 输出 true
    }
}

3. 懒汉式(线程不安全)

懒汉式单例模式的实现方式是在第一次调用getInstance()方法时创建单例对象,如果同时有多个线程并发调用该方法,可能会创建多个实例,因此这种实现方式是线程不安全的。

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

使用场景:适用于单例对象较大,多线程情况比较少的情况下。

示例:

public class Main {
    public static void main(String[] args) {
        Singleton instance1 = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance1 == instance2); // 输出 true
    }
}

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

为了解决线程安全问题,可以在getInstance()方法上添加synchronized关键字,保证多个线程调用该方法时只会创建一个单例对象,但是这种方式会降低并发性能。

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

使用场景:适用于单例对象较大,多线程情况比较多的情况下。

示例:

public class Main {
    public static void main(String[] args) {
        Singleton instance1 = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance1 == instance2); // 输出 true
    }
}

5. 懒汉式(线程安全,双重校验锁)

双重校验锁是目前线程安全的懒汉式单例模式实现方式,它采用了同步代码块和synchronized关键字的结合使用,解决了线程安全和并发性能问题。

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;
    }
}

使用场景:适用于单例对象较大,多线程情况比较多的情况下。

示例:

public class Main {
    public static void main(String[] args) {
        Singleton instance1 = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance1 == instance2); // 输出 true
    }
}

6. 枚举

枚举方式是目前最简单、最安全、最优雅的单例模式实现方式,它能够解决所有单例模式的问题,而且代码非常简洁明了。

public enum Singleton {
    INSTANCE;
    // 枚举类中的其他成员变量和成员方法
}

使用场景:适用于最简单、最安全、最优雅的单例模式实现方式。

示例:

public class Main {
    public static void main(String[] args) {
        Singleton instance1 = Singleton.INSTANCE;
        Singleton instance2 = Singleton.INSTANCE;
        System.out.println(instance1 == instance2); // 输出 true
    }
}

结语

以上就是Java中单例模式的六种实现方式,各有优缺点,需要根据具体情况选择。如果不要求延迟加载,可以选择饿汉式,否则应该选择懒汉式;如果需要保证线程安全,可以选择双重校验锁或枚举方式。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java单例模式的6种实现方式详解 - Python技术站

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

相关文章

  • spring batch使用reader读数据的内存容量问题详解

    下面是详细讲解“spring batch使用reader读数据的内存容量问题详解”的完整攻略。 1. 什么是Spring Batch Spring Batch是一个轻量级的综合批处理框架,用于开发企业级批处理应用程序。它允许开发人员能够处理大规模的数据,并且将这些数据转换成期望的格式,以便于后续处理。 2. Spring Batch读取器的内存容量问题 在S…

    Java 2023年6月3日
    00
  • JS实现上传文件显示进度条

    JS实现上传文件显示进度条的完整攻略: HTML部分 首先要有一个文件上传表单,可通过以下代码添加: <form name="form1" method="post" enctype="multipart/form-data" action="upload.php">…

    Java 2023年6月16日
    00
  • 详解Struts2中Action访问Servlet API的几种方法

    详解Struts2中Action访问Servlet API的几种方法 在Struts2框架中,我们可以通过在Action类中访问Servlet API来实现一些特殊操作。本文将详细介绍Struts2中Action访问Servlet API的几种方法。 方法一:继承ServletActionContext类 我们可以继承Struts2中的ServletActi…

    Java 2023年6月15日
    00
  • Java实现简单的表达式计算器功能示例

    Java实现简单的表达式计算器功能示例 在本攻略中,我们将介绍如何使用Java实现一个简单的表达式计算器。该计算器可以接受简单的算术表达式,并返回计算结果。我们将使用Java编程语言,其中包含有关如何使用Java变量、表达式、运算符和控制流的信息。 步骤1:创建项目并编写基本代码 你可以使用任何你熟悉或喜欢的Java开发工具来创建一个新项目。在这个项目中,你…

    Java 2023年5月18日
    00
  • SpringBoot实战教程之新手入门篇

    SpringBoot实战教程之新手入门篇攻略 SpringBoot是一种快速开发、简化配置的Java框架。它集成了常用的开发工具,如SpringMVC、Hibernate、MyBatis等,能够帮助开发人员快速搭建Java Web项目。本篇攻略将介绍学习SpringBoot的入门教程。 1. 安装Java和IDE 在开始学习SpringBoot之前,需要先安…

    Java 2023年5月15日
    00
  • 彻底解决Spring MVC中文乱码问题的方案

    彻底解决 Spring MVC 中文乱码问题的方案有以下几步: 第一步:在 web.xml 中添加 filter 在 web.xml 中添加如下过滤器,这个过滤器用于将所有请求和响应对象的编码都设置为 UTF-8: <filter> <filter-name>CharacterEncodingFilter</filter-nam…

    Java 2023年5月20日
    00
  • java运行shell脚本方法示例

    Java运行shell脚本方法 Java可以通过ProcessBuilder,Runtime和Process三种方式运行操作系统的命令,包括执行shell脚本。下面将详细讲解如何使用Java运行shell脚本。 方法一:ProcessBuilder ProcessBuilder可以创建一个进程来执行操作系统命令。可以通过设置ProcessBuilder的参数…

    Java 2023年5月23日
    00
  • 从源码角度深入解析Callable接口

    摘要:从源码角度深入解析Callable接口,希望大家踏下心来,打开你的IDE,跟着文章看源码,相信你一定收获不小。 本文分享自华为云社区《一个Callable接口能有多少知识点?》,作者: 冰 河。 并发编程一直是程序员们比较头疼的,如何编写正确的并发程序相比其他程序来说,是一件比较困难的事情,并发编程中出现的 Bug 往往也是特别诡异的。 之所以说并发编…

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