美文网首页
2_单例模式

2_单例模式

作者: 真是个点子王 | 来源:发表于2020-12-23 11:34 被阅读0次
    • 创建型模式:单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式;
    • 结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代码模式;
    • 行为型模式:模板方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、责任链模式

    单例模式

    • 单例模式就是采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得对象实例的方法。
    • Java写法分类
      • 饿汉式(静态常量)
      • 饿汉式(静态代码块)
      • 懒汉式(线程不安全)
      • 懒汉式(线程安全)
      • Double Check
      • 静态内部类
      • 枚举

    一、饿汉式(静态常量)

    • 步骤如下:
      • 1、构造器私有化;
      • 2、类的内部创建对象;
      • 3、向外暴露一个静态的方法;
      • 4、代码实现
    public class SingletonTest01 {
        public static void main(String[] args) {
            PersonManager manager = PersonManager.getInstance();
            PersonManager manager1 = PersonManager.getInstance();
            System.out.println(manager == manager1);
            System.out.println(manager.hashCode());
            System.out.println(manager1.hashCode());
        }
    }
    
    class PersonManager{
        // 2. 创建静态成员变量
        private static final PersonManager INSTANCE = new PersonManager();
        // 1. 将构造器私有化
        private PersonManager(){
        }
        // 3.提供一个静态方法,返回实例对象
        public static PersonManager getInstance() {
            return INSTANCE;
        }
    }
    

    优缺点:

    • 1、优点:写法简单,就是在类加载的时候就完成实例化。避免了线程同步问题;
    • 2、缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终未使用过这个实例,则会造成内存的浪费。
      • 关于类加载的机制,这一块还没有学习。需要留个坑,以及为何会存在线程同步问题,也不能够理解。

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

    • 这种方式原理和方式一中相同,只不过是将静态变量的初始化操作放在了静态代码块中。
    public class SingletonTest02 {
        public static void main(String[] args) {
            PersonManager02 manager = PersonManager02.getInstance();
            PersonManager02 manager1 = PersonManager02.getInstance();
            System.out.println(manager == manager1);
            System.out.println(manager.hashCode());
            System.out.println(manager1.hashCode());
        }
    }
    
    class PersonManager02{
    
        private static final PersonManager02 INSTANCE;
    
        static {
            INSTANCE = new PersonManager02();
        }
        private PersonManager02(){
    
        }
    
        public static PersonManager02 getInstance(){
            return INSTANCE;
        }
    

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

    • 在真正需要使用到类的对象的时候才去创建它。
    public class Singleton03 {
        public static void main(String[] args) {
            PersonManager03 manager = PersonManager03.getInstance();
            PersonManager03 manager1 = PersonManager03.getInstance();
            System.out.println(manager == manager1);
            System.out.println(manager.hashCode());
            System.out.println(manager1.hashCode());
        }
    
    }
    
    class PersonManager03{
        private static PersonManager03 instance;
        private PersonManager03(){
        }
        public static PersonManager03 getInstance(){
            if(instance == null){
                instance = new PersonManager03();
            }
            return instance;
        }
    }
    
    • 可以起到懒加载的效果,但是只能在单线程下使用;
    • 如果在多线程下,一个程序如果进入了if(instance == null)语句块,但是在还没有创建对象时,另外一个线程也进入了该块,会产生线程安全问题。

    四、懒汉式(线程安全)

    • getInstance()方法加上synchronized可以解决线程安全问题
    public class Singleton04 {
        public static void main(String[] args) {
            PersonManager04 manager = PersonManager04.getInstance();
            PersonManager04 manager1 = PersonManager04.getInstance();
            System.out.println(manager == manager1);
            System.out.println(manager.hashCode());
            System.out.println(manager1.hashCode());
        }
    }
    
    class PersonManager04{
        private static PersonManager04 instance;
        private PersonManager04(){
        }
        public static synchronized PersonManager04 getInstance(){
            if(instance == null){
                instance = new PersonManager04();
            }
            return instance;
        }
    }
    
    • 虽然解决了线程安全问题,但是效率太低。例如,后续操作可能只是单独的想获得该类的实例对象,但是每一次都需要进入到同步代码块中,太低效。

    五、Double Check

    public class Singleton05 {
        public static void main(String[] args) {
            PersonManager05 manager = PersonManager05.getInstance();
            PersonManager05 manager1 = PersonManager05.getInstance();
            System.out.println(manager == manager1);
            System.out.println(manager.hashCode());
            System.out.println(manager1.hashCode());
        }
    
    }
    
    class PersonManager05{
    
        private static volatile PersonManager05 instance;
        private PersonManager05(){
        }
        public static PersonManager05 getInstance(){
            if(instance == null){
                synchronized (PersonManager05.class){
                    if(instance == null) {
                        instance = new PersonManager05();
                    }
                }
    
            }
            return instance;
        }
    }
    

    六、静态内部类

    • 静态内部类在其所属的类加载时, 内部类本身不发生加载;
    • 当真正用到它时,才会加载(实现了延迟加载);
    • 在类加载时初始化,线程安全。
    • 步骤:
    public class SingletonTest06 {
        public static void main(String[] args) {
            PersonManager05 manager = PersonManager05.getInstance();
            PersonManager05 manager1 = PersonManager05.getInstance();
            System.out.println(manager == manager1);
            System.out.println(manager.hashCode());
            System.out.println(manager1.hashCode());
        }
    }
    
    class PersonManager06 {
     
        // 1、私有化构造器
        private PersonManager06(){
        }
    
        // 2、写一个静态内部类,该类中有一个静态属性Person
        private static class PersonInstance{
            private static final PersonManager06 INSTANCE = new PersonManager06();
        }
    
        // 3、提供一个静态的公有方法,直接返回Person.INSTANCE
        public static PersonManager06 getInstance(){
            return PersonInstance.INSTANCE;
        }
    }
    

    七、枚举

    public class SingletonTest07 {
        public static void main(String[] args) {
            PersonManager07 manager = PersonManager07.INSTANCE;
            PersonManager07 manager1 = PersonManager07.INSTANCE;
            System.out.println(manager == manager1);
            System.out.println(manager.hashCode());
            System.out.println(manager1.hashCode());
            manager.sayOK();
        }
    }
    
    enum PersonManager07{
        INSTANCE;
        public void sayOK(){
            System.out.println("ok");
        }
    }
    
    

    实例

    相关文章

      网友评论

          本文标题:2_单例模式

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