Java设计模式之单例模式

本文详细介绍了Java设计模式中的单例模式,包括定义、目的和注意事项。单例模式主要目的是节省资源,提高系统性能,适用于需要全局唯一对象的场景。文章列举并分析了八种单例实现方式,包括饿汉式、懒汉式、双重检查、静态内部类和枚举,推荐使用双重检查和静态内部类实现,因为它们既保证线程安全,又能实现延迟加载,提高效率。
摘要由CSDN通过智能技术生成

1. 单例模式概述

1.1 单例定义

所谓类的单例设计模式, 就是采取一定的方法保证在整个的软件系统中, 对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。
总结一句话,单例就是保证全局只有一个实例对象。

1.2 单例目的

使用单例可以避免重复创建对象,减少内存开销,提升系统性能

1.3 单例注意事项

  1. 单例模式保证了 系统内存中该类只存在一个对象, 节省了系统资源, 对于一些需要频繁创建销毁的对象, 使用单例模式可以提高系统性能。
  2. 当想实例化一个单例类的时候, 必须要记住使用相应的获取对象的方法, 而不是使用 new。
  3. 单例模式使用的场景: 需要频繁的进行创建和销毁的对象、 创建对象时耗时过多或耗费资源过多(即: 重量级对象), 但又经常用到的对象、 工具类对象、 频繁访问数据库或文件的对象(比如数据源、 session 工厂等)。

2.单例模式适用场景

单例模式只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等。如:
1.需要频繁实例化然后销毁的对象。
2.创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
3.有状态的工具类对象。
4.频繁访问数据库或文件的对象。

以下都是单例模式的经典使用场景:
1.资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
2.控制资源的情况下,方便资源之间的互相通信。如线程池等。

3.单例八种方式详解

单例模式总共有八种实现方式,总体分为饿汉式,懒汉式,双重检查,静态内部类与枚举五中类型。
其中饿汉式有2种,懒汉式3种,双重检查,静态内部类与枚举各1种。

1.饿汉式(静态常量,不推荐)

优缺点说明:
1) 优点: 这种写法比较简单, 就是在类装载的时候就完成实例化。 避免了线程同步问题。
2) 缺点: 在类装载的时候就完成实例化, 没有达到 Lazy Loading 的效果。 如果从始至终从未使用过这个实例, 则
会造成内存的浪费
3) 这种方式基于 classloder 机制避免了多线程的同步问题, 不过, instance 在类装载时就实例化, 在单例模式中大
多数都是调用 getInstance 方法, 但是导致类装载的原因有很多种, 因此不能确定有其他的方式(或者其他的静
态方法) 导致类装载, 这时候初始化 instance 就没有达到 lazy loading 的效果
4) 结论: 这种单例模式可用, 可能造成内存浪费

2.饿汉式(静态代码块,不推荐)

优缺点说明:
1) 这种方式和上面的方式其实类似, 只不过将类实例化的过程放在了静态代码块中, 也是在类装载的时候, 就执
行静态代码块中的代码, 初始化类的实例。 优缺点和上面是一样的。
2) 结论: 这种单例模式可用, 但是可能造成内存浪费

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

优缺点说明:
1) 这种方式和上面的方式其实类似, 只不过将类实例化的过程放在了静态代码块中, 也是在类装载的时候, 就执
行静态代码块中的代码, 初始化类的实例。 优缺点和上面是一样的。
2) 结论: 这种单例模式可用, 但是可能造成内存浪费

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

优缺点说明:
1) 解决了线程安全问题
2) 效率太低了, 每个线程在想获得类的实例时候, 执行 getInstance()方法都要进行同步。 而其实这个方法只执行
一次实例化代码就够了, 后面的想获得该类实例, 直接 return 就行了。 方法进行同步效率太低
3) 结论: 在实际开发中, 不推荐使用这种方式

5.懒汉式(线程安全, 同步代码块,不推荐)

不推荐使用

6.双重检查(推荐使用)

优缺点说明:
1) Double-Check 概念是多线程开发中常使用到的, 如代码中所示, 我们进行了两次 if (singleton == null)检查, 这
样就可以保证线程安全了。
2) 这样, 实例化代码只用执行一次, 后面再次访问时, 判断 if (singleton == null), 直接 return 实例化对象, 也避
免的反复进行方法同步.
3) 线程安全; 延迟加载; 效率较高
4) 结论: 在实际开发中, 推荐使用这种单例设计模式

7.静态内部类(推荐使用)

优缺点说明:
1) 这种方式采用了类装载的机制来保证初始化实例时只有一个线程。
2) 静态内部类方式在 Singleton 类被装载时并不会立即实例化, 而是在需要实例化时, 调用 getInstance 方法, 才
会装载 SingletonInstance 类, 从而完成 Singleton 的实例化。
3) 类的静态属性只会在第一次加载类的时候初始化, 所以在这里, JVM 帮助我们保证了线程的安全性, 在类进行
初始化时, 别的线程是无法进入的。
4) 优点: 避免了线程不安全, 利用静态内部类特点实现延迟加载, 效率高
5) 结论: 推荐使用.

8.枚举(推荐使用)

优缺点说明:
1) 这借助 JDK1.5 中添加的枚举来实现单例模式。 不仅能避免多线程同步问题, 而且还能防止反序列化重新创建
新的对象。
2) 这种方式是 Effective Java 作者 Josh Bloch 提倡的方式
3) 结论: 推荐使用

3.单例八种方式实现

package com.zrj.design.single;

/**
 * 单例模式,双重检查
 *
 * @author zrj
 * @date 2021/11/6
 * @since V1.0
 **/
public class Singleton {
    /**
     * 静态 volatile 修饰变量
     * 保证内存可见性
     * 禁止指令重排序
     */
    private static volatile Singleton instance;

    /**
     * 私有构造方法防止修改
     */
    private Singleton() {
    }

    /**
     * 双重校验锁
     */
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值