设计模式 创建型---单例模式

好久不见. 提交于 2019-12-22 20:48:50

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

单例模式作为设计模式中做常见的一种,这里代码也不重复了。

单例模式有9种实现方式,但是其中部分是有缺陷的。总结下来就是四种:

一、饿汉模式

/**
 * @ClassName: Singleton2
 * @description: 单例模式---饿汉模式(线程安全,但是不节省资源)
 * @author: edison_Kwok
 * @Date: create in 2019/12/10 22:59
 * @Version: 1.0
 */
public class Singleton2 {

    private static Singleton2 uniqueSingleton2 = new Singleton2();

    private Singleton2() {
    }

    public static Singleton2 getUniqueSingleton2() {
        //线程不安全问题主要是由于 uniqueInstance 被实例化多次,采取直接实例化 uniqueInstance 的方式就不会产生线程不安全问题。
        //但是直接实例化的方式也丢失了延迟实例化带来的节约资源的好处。
        return uniqueSingleton2;
    }
}

二、双重校验的懒汉模式

/**
 * @ClassName: Singleton4
 * @description: 单例模式---懒汉模式(双重校验锁-线程安全)
 * @author: edison_Kwok
 * @Date: create in 2019/12/10 23:09
 * @Version: 1.0
 */
public class Singleton4 {

    //uniqueInstance 采用 volatile 关键字修饰也是很有必要的, uniqueInstance = new Singleton(); 这段代码其实是分为三步执行:
    //
    //为 uniqueInstance 分配内存空间
    //初始化 uniqueInstance
    //将 uniqueInstance 指向分配的内存地址

    //使用 volatile 可以禁止 JVM 的指令重排,保证在多线程环境下也能正常运行。
    private volatile static Singleton4 uniqueSingleton4;

    private Singleton4() {
    }

    //uniqueInstance 只需要被实例化一次,之后就可以直接使用了。
    // 加锁操作只需要对实例化那部分的代码进行,只有当 uniqueInstance 没有被实例化时,才需要进行加锁。
    //双重校验锁先判断 uniqueInstance 是否已经被实例化,如果没有被实例化,那么才对实例化语句进行加锁。
    public static Singleton4 getUniqueSingleton4() {
        if (uniqueSingleton4 == null) {
            synchronized (Singleton4.class) {
                if (uniqueSingleton4 == null) {
                    //如果不加上里面这个null判断,可能就会出现两个线程在次等待
                    //两个线程都执行new命令
                    uniqueSingleton4 = new Singleton4();
                }
            }
        }
        return uniqueSingleton4;
    }
}

三、内部类

/**
 * @ClassName: Singleton5
 * @description: 静态内部类实现
 * @author: edison_Kwok
 * @Date: create in 2019/12/10 23:18
 * @Version: 1.0
 */
public class Singleton5 {

    private Singleton5() {
    }

    //当 Singleton 类被加载时,静态内部类 SingletonHolder 没有被加载进内存。
    private static class Singleton5Holder {
        //只有当调用 getUniqueInstance() 方法从而触发 SingletonHolder.INSTANCE 时 SingletonHolder 才会被加载
        // 此时初始化 INSTANCE 实例,并且 JVM 能确保 INSTANCE 只被实例化一次。
        private static final Singleton5 uniqueSingleton5 = new Singleton5();
    }

    public static Singleton5 getUniqueSingleton5() {
        //这种方式不仅具有延迟初始化的好处,而且由 JVM 提供了对线程安全的支持。
        return Singleton5Holder.uniqueSingleton5;
    }
}

四、枚举形式(大佬推荐)

/**
 * @ClassName: Singleton6
 * @description:
 * @author: edison_Kwok
 * @Date: create in 2019/12/22 20:32
 * @Version: 1.0
 */
public enum Singleton6 {
    instance;
}

class Client{
    public static void main(String[] args) {
        Singleton6 instance = Singleton6.instance;
    }
}

五、单例模式的注意事项和细节说明

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

六、单例模式在JDK源码

jdk中的java.lang.Runtime类

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!