您现在的位置是:首页 >其他 >设计模式-单例模式网站首页其他

设计模式-单例模式

Owen Guo 2024-06-20 06:51:33
简介设计模式-单例模式

单例模式

一提到单例模式必须要要先想到构造方法私有化,然后通过一个方法来获取这个对象的实例,且在一个进程中只会存在一份这个对象的实例。

在开发过程中其实有些对象我们是经常用到的,并且这个对象还不轻量,那我们就可以考虑使用单例模式,这个对象在内存中只会创建一次,后面使用的时候直接获取这个对象的实例,拿来使用就好了。

使用场景

需要频繁创建和销毁的对象、创建对象耗时过多或耗费资源过多(重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象。

单例模式的实现方法

1、饿汉式(静态常量)

class Singleton {

    // 1.构造方法私有化
    private Singleton() {}

    // 2.创建一个变量来保存实例对象
    private final static Singleton instance = new Singleton();

    // 3.通过一个公共的方法来获取这个对象
    public static Singleton getInstance() {
        return instance;
    }
}

优缺点:
1、写法简单,在类装载的时候就完成初始化。避免了线程同步问题。
2、容易造成内存浪费。

结论:
这种方法可用,但是可能造成内存浪费。

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

class Singleton {

    private static Singleton instance;

    private Singleton() {}

    // 这里通过静态代码块创建对象
    static {
        instance = new Singleton();
    }
    
    public static Singleton getInstance() {
        return instance;
    }
}

优缺点:
1、同上面一样,简单,避免了线程问题,但是会造成内存浪费。

结论:
可用,会造成内存浪费

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

class Singleton {

    private static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

优缺点:
1、起到了懒加载的效果,但是只能在单线程下面使用
2、在多线程下如果多个线程同事进入到了if (instance == null)判断语句块中,那么他们都会创建一个实例,这样返回的实例就不是同一个了。

结论:
在多线程环境下不能使用。

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

class Singleton {

    private static Singleton instance;

    private Singleton() {}

    // 在getInstance方法上增加synchronized,同时只能有一个线程执行该方法
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

优缺点:
1、解决了线程不安全的问题
2、效率太低,每一个线程执行都要通过锁,如果同一时刻线程很多,都会阻塞在这个方法这里。

结论:
可以使用,但是不推荐使用

5、懒汉式(线程安全,同步代码块)

class Singleton {

    private static Singleton instance;

    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            // 如果同时多个线程进入到这个判断语句块中
            // 那么只是在这个同步代码快这里阻塞一下,后面也是都会执行这个创建实例的
            // 线程不安全
            synchronized (Singleton.class) {
                instance = new Singleton();
            }
        }
        return instance;
    }
}

优缺点:
1、线程不安全。如果同时多个线程进入到判断语句块中,线程只是在这个同步代码快这里阻塞一下,后面也是都会执行这个创建实例的

结论:
线程不安全,不能使用这种方式

6、双重检查

class Singleton {

    // 这里的volatile很关键
    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;
    }
}

优缺点:
1、双重检查机制可以保证线程安全,我们在代码中进行了两次判断,在同步代码块中的代码同一时间只会有一个线程执行,下一个线程进来再判断一次就一定不会创建多个实例。
2、线程安全;延迟加载;效率高

结论:
可以使用,在实际开发中推荐使用这种方式

7、静态内部类

class Singleton {
    
    private Singleton() {}

    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {

        return SingletonInstance.INSTANCE;
    }
}

优缺点:
1、采用了类加载的机制来保证初始化实例的时候只有一个线程。
2、静态内部类在状态的时候并不会立即实例化,而是在需要的时候才会状态SingletonInstance内部类,从而完成Singleton的实例化
3、类的静态属性只会在第一次加载类的时候初始化,所以这里是JVM帮我们保证了线程安全,在类初始化的时候,别的线程是无法进入的。

结论:
线程安全,效率高,延迟加载。推荐使用

8、枚举

enum Singleton {
    INSTANCE;

    public void method() {
        System.out.println("枚举只会创建一个对象,都可以执行这个方法");
    }
}

优缺点:
1、借助枚举来实现单例模式,不仅能避免多线程问题,还能防止反序列化重新创建新对象。
2、是Effective Java作责Josh Bloch提倡的方式

结论:
推荐使用

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。