美文网首页
项目实战—那些年常用的单例模式

项目实战—那些年常用的单例模式

作者: 小胖学编程 | 来源:发表于2021-06-12 06:26 被阅读0次

常见的单例模式:饿汉式、懒汉式、双重检查锁模式、静态内部类实现单例模式、枚举单例模式,本文重点是在项目中如何实现上述的单例模式。

1. 饿汉式单例模式

饿汉式单例:类初始化时将单例对象加载到JVM中。

/**
 * 饿汉单例模式。
 * 类初始化时将单例对象加载到JVM中。
 */
@Slf4j
public class Singletoneh {
    private final static Singletoneh instance = new Singletoneh();

    private Singletoneh() {
    }

    public static Singletoneh getInstance() {
        return instance;
    }

    public void say() {
        System.out.println("【饿汉模式】—实现单例!");
    }

}

2. 懒汉式单例模式

懒汉式单例:并发写时,存在线程安全问题。进化版:双重检查锁模式

/**
 * 懒汉式单例
 */
public class Singletonlh {
    private static Singletonlh instance;
    private Singletonlh() {

    }
    public static Singletonlh getInstance() {
        if (instance == null) {
            instance = new Singletonlh();
        }
        return instance;
    }
    public void say() {
        System.out.println("【懒汉模式】—实现单例!");
    }
}

3. 双重检查锁模式

volatile关键字详见—Volatile可见性原理

/**
 * 双重检查锁模式
 * volatile 关键字:防止指令重排
 * <p>
 * 被volatile修饰的变量,会加一个lock前缀的汇编指令。
 * 若变量被修改后,会立刻将变量由工作内存回写到主存中。那么意味了之前的操作已经执行完毕。这就是内存屏障。
 */
public class SingletonOfSync2 {
    private static volatile SingletonOfSync2 instance;
    private SingletonOfSync2() {

    }
    /**
     * 双重检查模式,防止并发写时创建多个实例对象。
     * 使用volatile关键字防止指令重排;
     *
     * @return
     */
    public static SingletonOfSync2 getInstance() {
        if (instance == null) {
            synchronized (SingletonOfSync2.class) {
                if (instance == null) {
                    instance = new SingletonOfSync2();
                }
            }
        }
        return instance;
    }
    public void say() {
        System.out.println("【双重检查锁模式】—实现单例!");
    }
}

4. 静态内部类单例模式

由于 JVM 在加载外部类的过程中, 是不会加载静态内部类的, 只有内部类的属性/方法被调用时才会被加载, 并初始化其静态属性。静态属性由static修饰,保证只被实例化一次,并且严格保证实例化顺序。

/**
 * 静态内部类实现单例模式
 * <p>
 * 由于 JVM 在加载外部类的过程中, 是不会加载静态内部类的, 只有内部类的属性/方法被调用时才会被加载, 并初始化其静态属性。
 * 静态属性由static修饰,保证只被实例化一次,并且严格保证实例化顺序。
 */
public class SingletonOfInner {
    private SingletonOfInner() {

    }
    private static class InstanceHolder {
        private final static SingletonOfInner instance = new SingletonOfInner();
    }
    public static SingletonOfInner getInstance() {
        return InstanceHolder.instance;
    }
    public void say() {
        System.out.println("【静态内部类模式】—实现单例!");
    }
}

5. 枚举类单例模式

因为枚举类型是线程安全的,并且只会装载一次,设计者充分的利用了枚举的这个特性来实现单例模式。

public class SingletonOfEnum {

    //私有构造方法
    private SingletonOfEnum() {

    }
    /**
     * 枚举类返回单例对象
     */
    public static SingletonOfEnum getInstance() {
        return Singleton.INSTANCE.getInstance();
    }

    private enum Singleton {

        INSTANCE;

        private final SingletonOfEnum instance;

        Singleton() {
            instance = new SingletonOfEnum();
        }

        private SingletonOfEnum getInstance() {
            return instance;
        }

    }

    public void say() {
        System.out.println("【枚举模式】—实现单例!");
    }

}

6. 破坏单例模式以及解决方案

6.1 反射破坏

public class testSingleton {
    public static void main(String[] args) throws Exception {

        Constructor<Singletoneh> co1 = Singletoneh.class.getDeclaredConstructor();
        co1.setAccessible(true);
        Singletoneh s1 = co1.newInstance();
        s1.say();

        Constructor<Singletoneh> co2 = Singletoneh.class.getDeclaredConstructor();
        co2.setAccessible(true);
        Singletoneh s2 = co2.newInstance();
        s2.say();

        System.out.println("单例对象是否相等:" + (s1 == s2));
        
    }
}
image.png

除枚举方式外, 其他方法都会通过反射的方式破坏单例,反射是通过调用构造方法生成新的对象,所以如果我们想要阻止单例破坏,可以在构造方法中进行判断,若已有实例, 则阻止生成新的实例,解决办法如下:

    private Singletoneh() {
        if(instance!=null){
            throw new RuntimeException("单例对象已经存在");
        }
    }

6.2 序列化接口Serializable

如果单例类实现了序列化接口Serializable, 就可以通过反序列化破坏单例,所以我们可以不实现序列化接口,如果非得实现序列化接口,可以重写反序列化方法readResolve(), 反序列化时直接返回相关单例对象。

public Object readResolve() throws ObjectStreamException {
    return instance;
}

推荐阅读

枚举类来实现单例模式

相关文章

  • 项目实战—那些年常用的单例模式

    常见的单例模式:饿汉式、懒汉式、双重检查锁模式、静态内部类实现单例模式、枚举单例模式,本文重点是在项目中如何实现上...

  • 【设计模式】单例模式

    单例模式 常用单例模式: 懒汉单例模式: 静态内部类单例模式: Android Application 中使用单例模式:

  • Spring Boot 单例模式中依赖注入问题

    在日常项目开发中,单例模式可以说是最常用到的设计模式,项目也常常在单例模式中需要使用 Service 逻辑层的方法...

  • iOS面试题系列之Objective-C相关

    1、简述你项目中常用的设计模式。它们有什么优缺点?常用的设计模式有:代理、观察者、单例。(1)单例:它是用来限制一...

  • OC通用单例模式宏文件以及使用方法

    项目中,我们经常用到单例模式,并且不止一个类需要建立单例模式,为了方便快速创建单例模式类,编写如下宏。 使用方法很...

  • Android开发学习——Day10(单例设计模式&实战:扑克游

    学习目的 1.学习单例设计模式 2.完善并练习实战项目:扑克游戏 学习过程 了解单例设计模式,并简单运用。完善之前...

  • 单例模式

    单例模式 最常用的单例模式,经常在项目中见,梳理后发现各种各样的单例,索性梳理一下。 自己创建自己,提供了访问其唯...

  • Node.js与单例模式

    1、前端的JavaScript单例模式 单例模式是非常常用的设计模式,前端的JavaScript中单例模式代码可能...

  • IOS学习笔记之单例

    单例介绍 1.什么是单例 说到单例首先要提到单例模式,因为单例模式是单例存在的目的 单例模式是一种常用的软件设计模...

  • IOS开发过程中常用的设计模式

    当下IOS开发的过程中,常用的设计模式有:单例模式、委托模式、观察者模式和MVC模式; 一、单例模式 我们平时常用...

网友评论

      本文标题:项目实战—那些年常用的单例模式

      本文链接:https://www.haomeiwen.com/subject/nxkpeltx.html