ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

设计模式 --- 单例模式

2021-09-05 21:00:31  阅读:129  来源: 互联网

标签:void System --- INSTANCE static 单例 println 设计模式 public


应用场景

只需要一个实例,在代码和内存方面只希望它有一个实例出来

关键点

第一:构造方法设计成私有的

        无法new 出来

第二:提供获取实例的方法

相关概念

1.class.forName("")可以加载类名,静态变量load到内存,就会实例化

2.哈希码相同也不一定是同一个对象

3.final修饰的变量 必须要初始化

写法相关

饿汉式

优点:类加载到内存 就实例化一个单利 jvm保证线程安全,简单实用

缺点:不管用到与否,类装载时就完成了实例化

代码块

public class Single1 {
    private static final Single1 INSTANCE = new Single1();

    private  Single1() {};

    public static Single1 getINSTANCE() {
        return INSTANCE;
    }

    public void m() {System.out.println("m");}

    public static void main(String[] args) {
        Single1 m1 = Single1.getINSTANCE();
        Single1 m2 = Single1.getINSTANCE();
        System.out.println(m1 == m2);
    }
}

懒汉式

优点:达到了按需加载的目的

缺点:带来了线程不安全的问题

代码块

public class Single2 {
    //如果加 final 必须要初始化
    private static Single2 INSTANCE;

    private Single2() {}

    public static Single2 getINSTANCE() {
        if (INSTANCE == null) {
            try {
                //睡一毫秒 都会产生对象的不同的实例化实例
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            INSTANCE = new Single2();
        }
        return INSTANCE;
    }

    public void m() {
        System.out.println("m");
    }

    public static void main(String[] args) {
        for (int i=0; i<100; i++) {
            new Thread(()-> {
                System.out.println(Single2.getINSTANCE().hashCode());
                //不同对象的哈希码是不同的
            }).start();
        }
    }
}

以下几个代码段是进阶版的饿汉式

加上synchronized 锁定了当前语句块,但是效率下降

代码块

public class Single3 {
    //如果加 final 必须要初始化
    private static Single3 INSTANCE;

    private Single3() {}

    //每次都加锁 效率就降低了
    public static synchronized Single3 getINSTANCE() {
        if (INSTANCE == null) {
            try {
                //睡一毫秒 都会产生对象的不同的实例化实例
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            INSTANCE = new Single3();
        }
        return INSTANCE;
    }

    public void m() {
        System.out.println("m");
    }

    public static void main(String[] args) {
        for (int i=0; i<100; i++) {
            new Thread(()-> {
                System.out.println(Single3.getINSTANCE().hashCode());
                //不同对象的哈希码是不同的
            }).start();
        }
    }
}

通过减小同步代码块的方式提高效率,多线程情况下也不能做到同一个实例

代码块

public class Single4 {
    //如果加 final 必须要初始化
    private static Single4 INSTANCE;

    private Single4() {}

    //每次都加锁 效率就降低了
    public static Single4 getINSTANCE() {
        if (INSTANCE == null) {
            synchronized (Single4.class) {
                try {
                    //睡一毫秒 都会产生对象的不同的实例化实例
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                INSTANCE = new Single4();
            }
        }
        return INSTANCE;
    }

    public void m() {
        System.out.println("m");
    }

    public static void main(String[] args) {
        for (int i=0; i<100; i++) {
            new Thread(()-> {
                System.out.println(Single4.getINSTANCE().hashCode());
                //不同对象的哈希码是不同的
            }).start();
        }
    }
}

双重检查单例判断

代码块

public class Single5 {
    //如果加 final 必须要初始化 volatile 禁止指令重排
    private static volatile Single5 INSTANCE;

    private Single5() {}

    //每次都加锁 效率就降低了
    public static Single5 getINSTANCE() {
        if (INSTANCE == null) {
            synchronized (Single5.class) {
                //双重检查
                if (INSTANCE == null) {
                    try {
                        //睡一毫秒 都会产生对象的不同的实例化实例
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    INSTANCE = new Single5();
                }

            }
        }
        return INSTANCE;
    }

    public void m() {
        System.out.println("m");
    }

    public static void main(String[] args) {
        for (int i=0; i<100; i++) {
            new Thread(()-> {
                System.out.println(Single5.getINSTANCE().hashCode());
                //不同对象的哈希码是不同的
            }).start();
        }
    }
}

静态内部类方式

相关知识点:

1.jvm保证单例,加载外部类时不会加载内部类,可以实现懒加载

2.私有化,只有内部类才可以new出来、

3.内部类不会被随便加载,被调用时才会进行加载

4.虚拟机加载一个class的时候,只加载一次

代码块

public class Single6 {
    private Single6() {}

    private static class Single6Holder {
        private final static Single6 INSTANCE = new Single6();
    }

    public static Single6 getInstance() {
        return Single6Holder.INSTANCE;
    }

    public void m() {
        System.out.println("m");
    }

    public static void main(String[] args) {
        for (int i=0; i<100; i++) {
            new Thread(()->{
                System.out.println(Single6.getInstance().hashCode());
            }).start();
        }

    }
}

枚举类方式

相关知识点:

1.不仅可以解决线程同步,还可以防止反序列化

2.单例 防止反序列化,把类反射,load到内存

3.不会被反序列化的原因是:枚举类没有构造方法,就算是反序列化只会拿到枚举类的值

4.语法上是最完美的

代码块

public enum Single7 {

    INSTANCE;

    public void m() {}

    public static void main(String[] args) {
        for (int i=0;i<100; i++) {
            new Thread(()->{
                System.out.println(Single7.INSTANCE.hashCode());
            }).start();
        }
    }
}

相关

spring框架中的bean工厂来保证单例 

标签:void,System,---,INSTANCE,static,单例,println,设计模式,public
来源: https://blog.csdn.net/weixin_38738277/article/details/120120785

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有