zoukankan      html  css  js  c++  java
  • 【设计模式学习笔记】单例模式

    单例设计模式介绍

      单例设计模式,就是采取一定的方法保证整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个其对象的实例方法。

    单例模式八种实现方式

    • 饿汉式(静态常量)
    • 饿汉式(静态代码块)
    • 懒汉式(线程不安全)
    • 懒汉式(线程安全,同步方法)
    • 懒汉式(线程安全,同步代码块)
    • 双重检查
    • 静态内部类
    • 枚举

    饿汉式(静态常量)

    • 步骤如下
      •  构造器私有化(防止用户new对象)
      • 在类的内部创建对象
      • 向外暴露一个静态的公共方法getInstance
    public class Solution {
        public static void main(String[] args) {
            Singleton singleton = Singleton.getInstance();
            Singleton singleton1 = Singleton.getInstance();
            System.out.println(singleton == singleton1); // true
            System.out.println(singleton); // Singleton@1b6d3586
            System.out.println(singleton1); // Singleton@1b6d3586
        }
    }
    class Singleton {
        // 私有化构造器
        private Singleton() {}
        // 创建对象
        private static final Singleton instance = new Singleton();
        // 静态公共方法
        public static Singleton getInstance() {
            return instance;
        }
    }
    • 优点:在类装载的时候就完成实例化,避免了线程同步的问题。
    • 缺点:在类装载的时候就完成实例化对象,没有懒加载的效果。如果一直没有使用过这个对象,就会造成内存的浪费

    饿汉式(静态代码块)

    public class Solution {
        public static void main(String[] args) {
            Singleton singleton = Singleton.getInstance();
            Singleton singleton1 = Singleton.getInstance();
            System.out.println(singleton == singleton1); // true
            System.out.println(singleton); // Singleton@1b6d3586
            System.out.println(singleton1); // Singleton@1b6d3586
        }
    }
    class Singleton {
        private Singleton() {}
        private static final Singleton instance;
        static {
            instance = new Singleton();
        }
        public static Singleton getInstance() {
            return instance;
        }
    }

    懒汉式(线程不安全)

    class Singleton {
        private static Singleton instance;
        private Singleton() {}
        public static Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    • 优点:起到了懒加载的效果,但是只能在单线程下使用
    • 缺点:如果在多线程的环境下,当两个线程同时进入instance == null那么此时就有可能创建两个不同的对象

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

    class Singleton {
        private static Singleton instance;
        private Singleton() {}
        public synchronized static Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    • 优点:解决线程安全问题
    • 缺点:效率低,多线程情况下,每一个线程在获得实例的时候在调用方法的时候都要进行同步。实际上这个方法只执行一次实例化的方法即可,后面如果想要再次获得对象只需要直接返回即可。但是上面这种方式,在线程没有拿到锁的时候都要进行等待。

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

    class Singleton {
        private static Singleton instance;
        private Singleton() {}
        public static Singleton getInstance() {
            if (instance == null) {
                synchronized (Singleton.class) {
                    instance = new Singleton();
                }
            }
            return instance;
        }
    }
    • 这种方式会引起线程安全问题,在多线程并发的情况下,可能创建两个不同的实例。

    双重检查

    class Singleton {
        // volatile 保证了可见性和有序性,可以让修改值立即更新到主存
        private volatile static Singleton instance;
        private Singleton() {}
        public static Singleton getInstance() {
            if (instance == null) {
                synchronized (Singleton.class) {
                    if (instance == null) {
                        instance = new Singleton();
                        // 在堆内存分配对象的内存空间
                        // 在堆内存上初始化对象
                        // 设置 instance 指向刚分配的内存地址
                        // 上面两步可能发生指令重排序,可能造成 instance 无法指向正常的对象
                        // 所以需要加入 volatile 关键字
                    }
                }
            }
            return instance;
        }
    }
    • 这种方式在多线程开发中经常用到,进行了两次检查,可以解决线程安全问题。
    • 上述代码,实例化代码只执行一次,避免反复的进行方法同步,线程安全,延迟加载,效率较高
    • 在实际开发的过程中,比较推荐这种单例设计模式。

    静态内部类

    class Singleton {
        // 当 Singleton 进行类加载的时候,静态内部类不会被加载
        private Singleton() {}
        public static class SingletonInstance {
            private static final Singleton INSTANCE = new Singleton();
        }
        public static Singleton getInstance() {
            return SingletonInstance.INSTANCE;
            // 使用 SingletonInstance 会被装载,只会装载一次
        }
    }
    • 这种方式采用类装载机制来保证初始化实例的时候只有一个线程。
    • 静态内部类在Singleton装载的时候,静态内部类不会被加载,在需要调用getInstance方法的时候才会被加载。因为在类加载的时候其中的静态属性只会被加载一次,所以这里JVM可以保证线程安全性,在类进行初始化的时候其他线程是无法进入的。
    • 避免了线程不安全,利用静态内部类的特点实现了延迟加载,效率比较高

    枚举

    public class SingletonTest {
        public static void main(String[] args) {
            Singleton singleton = Singleton.INSTANCE;
            Singleton singleton1 = Singleton.INSTANCE;
            System.out.println(singleton == singleton1); // true
            System.out.println(singleton.hashCode()); // 460141958
            System.out.println(singleton1.hashCode()); // 460141958
        }
    }
    // 枚举,使用枚举可以实现单例
    enum Singleton {
        INSTANCE;
    }
    • 借助JDK 1.5中的枚举来实现单例模式,能够避免线程同步问题,而且能够防止反序列化重新创建新的对象。

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

    • 单例模式保证了系统内存中该类只存在一个对象,节省了系统的资源,对于一些需要频繁创建和销毁的对象,使用单例模式可以提升系统性能。
    • 当想要实例化一个单例类的时候,需要记住相应的获取对象的方法。
    • 使用场景:需要频繁创建和销毁对象、创建对象耗时过多的时候或者耗费资源过多(重量级对象)的时候,但是又经常使用的对象、工具类对象、频繁访问数据库的对象或者文件的对象。例如:数据源、session工厂等。
  • 相关阅读:
    Linux服务器查看日志命令总结
    nginx高可用(5)
    nginx动静分离(4)
    nginx负载均衡(3)
    nginx反向代理(2)
    nginx安装及使用(1)
    Nginx 简易教程
    uiautomator2中文文档
    TKinter之输入框
    nginx解决反向代理session丢失问题
  • 原文地址:https://www.cnblogs.com/zut-syp/p/14290905.html
Copyright © 2011-2022 走看看