• 单例模式的介绍和五种写法


    1.介绍

    单例模式,是23中设计模式中比较重要的设计模式,单例其实就是单一实例,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。

    java中的RunTime类就使用了单例模式

    2.写法

       1)饿汉式     

    1. public class Singleton {
    2. /**
    3. * 1)构造器私有化
    4. * 2)自行创建,并且用静态变量保存
    5. * 3)对外提供这个实例
    6. * 4)强掉这是一个单例,我们可以用final修饰
    7. */
    8. public static final Singleton INSTANCE = new Singleton();
    9. private Singleton(){
    10. }
    11. }
    12. public class MainTest {
    13. public static void main(String[] args) {
    14. Singleton instance=Singleton.INSTANCE;
    15. Singleton instance1 = Singleton.INSTANCE;
    16. System.out.println(instance);
    17. System.out.println(instance1);
    18. }
    19. }
    20. //控制台输出
    21. cn.nlg.test.Singleton@1540e19d
    22. cn.nlg.test.Singleton@1540e19d

      特点:

           a)在这个类初始化时就创建了对象, 每次调用都返回同一个对象

           b)如果没有使用到这个对象会浪费内存空间

       2)懒汉式

    1. public class Singleton {
    2. private static Singleton instance = null;
    3. private Singleton() {
    4. }
    5. //这里多线程环境下会有线程安全问题,单线程没问题
    6. public static Singleton getInstance() {
    7. if(instance == null){
    8. instance =new Singleton();
    9. }
    10. return instance;
    11. }
    12. }
    13. public class MainTest {
    14. public static void main(String[] args) {
    15. Singleton instance=Singleton.getInstance();
    16. Singleton instance1 = Singleton.getInstance();
    17. System.out.println(instance);
    18. System.out.println(instance1);
    19. }
    20. }
    21. //控制台输出
    22. cn.nlg.test.Singleton@1540e19d
    23. cn.nlg.test.Singleton@1540e19d

    特点:  多线程的环境下会存在线程安全问题这个适用于单线程

       3)双检锁

    1. class Singleton {
    2. public volatile static Singleton instance = null;
    3. public Singleton(){ }
    4. public static Singleton getInstance(){
    5. //外层判断是为了让instance不为空时无需等待
    6. if(instance == null){
    7. //使用synchronized关键字,保证了每次只有一个线程操作
    8. synchronized (Singleton.class){
    9. if(instance == null){
    10. instance = new Singleton();
    11. }
    12. }
    13. }
    14. return instance;
    15. }
    16. }
    17. //主方法测试
    18. public class MainTest {
    19. public static void main(String[] args) {
    20. Singleton instance=Singleton.getInstance();
    21. Singleton instance1 = Singleton.getInstance();
    22. System.out.println(instance);
    23. System.out.println(instance1);
    24. }
    25. }
    26. //控制台输出
    27. cn.nlg.test.Singleton@1540e19d
    28. cn.nlg.test.Singleton@1540e19d

     特点:1)解决了线程安全问题

                b)volatile是为了防止指令重排,可以去了解一下volatile关键字的作用

       4)静态内部类     

    1. public class Singleton{
    2. private Singleton(){}
    3. //静态内部类
    4. private static class Inner{
    5. private static Singleton INSTANCE = new Singleton();
    6. }
    7. public static Singleton getInstance(){
    8. return Inner.INSTANCE;
    9. }
    10. }
    11. //主方法测试
    12. public class MainTest {
    13. public static void main(String[] args) {
    14. Singleton instance=Singleton.getInstance();
    15. Singleton instance1 = Singleton.getInstance();
    16. System.out.println(instance);
    17. System.out.println(instance1);
    18. }
    19. }
    20. //控制台输出
    21. cn.nlg.test.Singleton@1540e19d
    22. cn.nlg.test.Singleton@1540e19d

      特点:a)这是懒汉式中比较推荐的写法

                 b)外部类加载时并不需要立即加载内部类,内部类不被加载则不去初始化INSTANCE

       5)枚举

    1. public enum Singleton {
    2. INSTANCE;
    3. }
    4. //主方法测试
    5. public class MainTest {
    6. public static void main(String[] args) {
    7. Singleton instance=Singleton.INSTANCE;
    8. Singleton instance1 =Singleton.INSTANCE;
    9. System.out.println(instance);
    10. System.out.println(instance1);
    11. }
    12. }
    13. 重写了toString方法,控制台输出
    14. INSTANCE
    15. INSTANCE

      特点 :a) enum 类型是线程安全的,因为Java 类的加载和初始化过程都是线程安全的(反编译一下枚举类)

                  b)饿汉式中比较推荐的写法

       例子:

          枚举类:

    1. public enum T {
    2. SPRING,SUMMER,AUTUMN,WINTER;
    3. }

        反编译之后的枚举类:

    1. public final class T extends Enum
    2. {
    3. //省略部分内容
    4. public static final T SPRING;
    5. public static final T SUMMER;
    6. public static final T AUTUMN;
    7. public static final T WINTER;
    8. private static final T ENUM$VALUES[];枚举类型和泛型 < 228
    9. static
    10. {
    11. SPRING = new T("SPRING", 0);
    12. SUMMER = new T("SUMMER", 1);
    13. AUTUMN = new T("AUTUMN", 2);
    14. WINTER = new T("WINTER", 3);
    15. ENUM$VALUES = (new T[] {
    16. SPRING, SUMMER, AUTUMN, WINTER
    17. });
    18. }
    19. }

    1.枚举类型T不可被继承
    2.T中所有属性都被 static final 修饰

  • 相关阅读:
    CarSim-车辆模型
    C++学习日记——函数指针
    以用户需求为核心能玩出什么新花样?魅族 19 主理人计划构建理想机型
    PCI bar 解析
    排序算法之【快速排序】
    curl命令行发送post/get请求
    Dubbo-Activate实现原理
    使用kubeadm快速部署一个K8s集群
    Centos 常用软件的安装与配置精简版
    工具: MarkDown学习
  • 原文地址:https://blog.csdn.net/weixin_57869541/article/details/126962280