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日

相关文章

  • Java8 新特性Lambda表达式实例详解

    Java8 新特性Lambda表达式实例详解 Java8 新特性Lambda表达式,是一个非常强大的工具。它可以让我们编写出更加简洁清晰易懂的代码,并且大大提高了代码编写的效率。在本文中,我将详细讲解Lambda表达式的语法和使用方法,并通过两个实例帮助您更好地理解这个新特性。 Lambda表达式的语法 Lambda表达式的语法非常简单,它由三个部分构成:参…

    Java 2023年5月26日
    00
  • 启动tomcat时 错误: 代理抛出异常 : java.rmi.server.ExportException: Port already in use: 1099的解决办法

    如果在启动Tomcat时出现“错误: 代理抛出异常: java.rmi.server.ExportException: Port already in use: 1099”的错误,意味着端口1099已经被占用了。一般是因为其他应用程序或Tomcat已经在使用该端口,导致Tomcat无法使用。 解决该问题的方法有两种,一种是找到占用了端口1099的应用程序并关…

    Java 2023年5月27日
    00
  • Spring Security UserDetails实现原理详解

    Spring Security UserDetails实现原理详解 Spring Security 是一个功能强大的安全框架,它的核心是 Spring Security 核心包。其中,UserDetails 是 Spring Security 中的一个核心接口,它包含了用户信息以及授权信息等内容。本文将详细讲解 Spring Security UserDet…

    Java 2023年5月20日
    00
  • springMVC实现文件上传和下载

    下面我将详细讲解 Spring MVC 实现文件上传和下载的完整攻略。 文件上传 准备工作 在 Spring MVC 中,文件上传需要使用 MultipartResolver 接口来进行解析。常用的实现类有两种,分别是: StandardServletMultipartResolver:使用 Servlet API(3.0)中的 Part 接口进行文件上传解…

    Java 2023年6月15日
    00
  • Spring Data Jpa 自动生成表结构的方法示例

    首先,我们需要先了解Spring Data Jpa自动生成表结构的方法。Spring Data Jpa是Spring框架中的一个重要组成部分,它提供了一种方便快捷的方式来管理和操作数据库中的数据。 Spring Data Jpa可以自动生成表结构,这样就不需要手动编写SQL语句来创建表了。具体的步骤如下: 配置数据源 在你的Spring应用程序中,你需要首先…

    Java 2023年5月20日
    00
  • jsp页面验证码完整实例

    下面是关于”JSP页面验证码完整实例”的完整攻略: 1. 流程介绍 验证码是一种常见的安全验证,可以有效地防止机器人程序以及恶意攻击。在 JSP 页面中,使用验证码可以有效地保障数据的安全性。 本文将介绍如何在 JSP 页面中实现验证码的功能,包括生成随机验证码、将验证码展示在页面中、验证用户输入的验证码是否正确等。具体流程如下: 用户在页面中填写用户名、密…

    Java 2023年6月15日
    00
  • js使用xml数据载体实现城市省份二级联动效果

    下面是使用XML数据载体实现城市省份二级联动效果的完整攻略: 1. 准备XML数据源 首先,我们需要准备一个XML文件作为数据源。XML是一种标记语言,可以方便地描述数据结构。这里我们以中国省市县三级行政区划数据作为示例。可以从许多数据开放平台或者政府官网上获取到相应的数据,如国家统计局。然后,我们可以将数据整理成以下格式(也可以根据自己需求来进行修改): …

    Java 2023年6月15日
    00
  • Struts2 通过ognl表达式实现投影

    下面是详细的讲解: 概述 Struts2 是一个优秀的 Java Web 应用框架,它的表单标签库可以很方便地实现表单的输入和输出。但有时候,我们也需要一些特殊的操作,比如使用投影(projection)来显示指定的数据,此时,ognl 表达式就可以派上用场了。 步骤 1. 配置Struts2引用ognl 在 struts.xml 文件中配置如下: <…

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