单例模式

单例模式

定义

一个类有且仅有一个实例,并且自行实例化向整个系统提供。(创建型模式)设计模式中比较简单的几种之一,单例模式就是让一个类在系统运行过程中只会产生唯一的一个实例,单例模式主要:

  1. 单例类只能有一个实例。
  2. 单例类必须自己创建自己的唯一实例。
  3. 单例类必须给所有其他对象提供这一实例。

使用场景

  • 需要频繁实例化然后销毁的对象。
  • 创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
  • 有状态的工具类对象。
  • 频繁访问数据库或文件的对象。

单例模式的实现

单例模式的实现一般根据实例化对象时的不同分为懒汉式和饿汉式.

懒汉式典型实现

package factory.pattern.singleton;
/**
 * Created by fk5431 on 6/19/17.
 */
public class SingletonLazy {
    private static SingletonLazy singletonLazy;
    private SingletonLazy (){}
    public static SingletonLazy getInstance(){
        if( singletonLazy == null){
            singletonLazy = new SingletonLazy();
        }
        return singletonLazy;
    }
}

懒汉式的模式就是在需要进行实例化的时候在进行实例化,这种方式在多线程的时候是有问题的,会有线程安全问题.

懒汉式线程安全形式

package factory.pattern.singleton;
/**
 * Created by fk5431 on 6/19/17.
 */
public class SingletonLazeSafe {
    private static SingletonLazeSafe singletonLazeSafe;
    private SingletonLazeSafe(){}
    public static synchronized SingletonLazeSafe getInstance(){
        if(singletonLazeSafe == null){
            singletonLazeSafe = new SingletonLazeSafe();
        }
        return singletonLazeSafe;
    }
}

懒汉式的线程安全模式在进入获取实例方法时候就会加synchronize,可以保证线程安全获取唯一的实例,但是如果该方法调用过多会有性能方面的影响.

饿汉式

package factory.pattern.singleton;
/**
 * Created by fk5431 on 6/19/17.
 */
public class SingletonHungary {
    private static SingletonHungary singletonHungary = new SingletonHungary();
    private SingletonHungary(){}
    public static SingletonHungary getInstance(){
        return singletonHungary;
    }
}

饿汉式会在类装载时候就进行实例的初始化,虽然没有了synchronize的效率影响,但是在类加载的时候就进行了初始化一方面浪费了内存,也没有实现lazy loading加载的效果.

双重校验锁

package factory.pattern.singleton;
/**
 * Created by fk5431 on 6/19/17.
 */
public class DoubleCheckedLocking {
    private static DoubleCheckedLocking doubleCheckedLocking;
    private DoubleCheckedLocking(){}
    public DoubleCheckedLocking getInstance(){
        if(doubleCheckedLocking == null){
            synchronized (DoubleCheckedLocking.class){
                if(doubleCheckedLocking == null){
                    doubleCheckedLocking = new DoubleCheckedLocking();
                }
            }
        }
        return doubleCheckedLocking;
    }
}

这种方式采用了双锁机制,一方面保证了多线程的安全,另一方面还提高了效率.但是看起来是完美,但是实际上这种方式是有缺陷的,是错误的一种.(双重检查锁定的问题下次专门写个文章)

静态内部类

package factory.pattern.singleton;
/**
 * Created by fk5431 on 6/19/17.
 */
public class SingletonStaticClass {
    //静态内部类
    private static class SingletonHodler{
        private static final SingletonStaticClass INSTANCE = new SingletonStaticClass();
    }
    private SingletonStaticClass(){}
    public static final SingletonStaticClass getInstance(){
        return SingletonHodler.INSTANCE;
    }
}

这种方式利用了 classloder 机制来保证初始化 instance 时只有一个线程,但是这个是类装载的时候不一定会进行初始化,只有在调用 getInstance 方法时候才会显示的装载SingletonHodler,然后实例化instance.

枚举的方式

public enum EnumSingleton {
    INSTANCE;
}

枚举的方式最简单,又是线程安全的(默认枚举实例的创建是线程安全的)

#设计模式#
设计模式介绍 文章被收录于专栏

设计模式是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。其实就是经过前人反复使用总结使用得出在不同场景有对应的解决方案。

全部评论

相关推荐

一面 一、数据库相关1. 数据库的索引是什么?为什么使用索引?InnoDB的数据索引基于什么实现?2. B+树和B树的差异?3. B+树查询一次的时间复杂度是多少?4. 哈希数据结构的查询时间复杂度?5. MySQL为什么不使用哈希结构?6. 主键设计为什么一般用自增ID,而非身份证号等业务字段?二、进程、线程、协程相关1. 进程、线程、协程的定义?为什么需要协程?2. 两个线程修改共享变量的线程安全问题如何解决?3. 悲观锁和乐观锁的差别?三、TCP/UDP网络相关1. TCP和UDP的核心区别及应用场景?2. 滑动窗口机制的原理?3. 已发送但未收到ACK的问题如何解决?4. TCP三次握手能否改为两次,加超时重试?四、登录系统设计相关1. 支持30天免登录的数据库表设计(表数量、作用、主键、索引)?2. 前端与客户端交互中如何实现30天免登录?3. 是否了解SSO?4. 用户登录态的设计实现有哪几种?是否了解JWT?五、限流与缓存相关1. 高峰期如何避免流量打挂服务/底层存储(从限流和缓存角度)?2. 是否了解令牌桶和漏桶算法的实现、区别及适用场景?3. 缓存击穿和缓存穿透的区别及解决方法?4. 布隆过滤器的原理及误判解决/降低方法?六、Redis相关1. Redis的基本数据类型有哪些?2. set和zset的区别?3. zset的原理?七、其他技术相关1. 是否了解AI Coding(如OpenAI工具、Spectacle Coding、Web Coding)?Spectacle Coding解决了哪些问题?2. 是否接触过Go语言?
查看26道真题和解析
点赞 评论 收藏
分享
评论
6
14
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务