java-设计模式-单例模式

单例模式

  • 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。

  • 属于创建型模式,提供了一种创建对象的最佳方式。

  • 一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建,提供唯一的对象访问方式方式,可以直接访问,不需要实例化该类的对象。

  • 注意:

    • 单例类只能有一个实例。
    • 单例类必须自己创建自己的唯一实例。
    • 单例类必须给所有其他对象提供这一实例。

饿汉式单例

  • 饿汉式单例是单例模式中最简单的一种单例实现

  • 饿汉式单例在类加载的时候就会对类对象进行加载,但会浪费内存资源,属于常用方式,但容易产生垃圾对象

  • 饿汉式单例基于java的classloader机制实现了多线程安全

    实现

    public class Hungry {
        //单例模式-->饿汉式
        //私有化无参构造器
        private Hungry(){}
       
        //创建私有类对象
        private static Hungry hungry = new Hungry();
    
        //将类对象返回
        public static Hungry getInstance(){
            return hungry;
        }
    }
    

懒汉式单例

  • 属于单例模式的一种基本实现,类加载时不会自动加载,

    public class Lazy {
    
        //创建私有类实例
        private static Lazy lazy;
    
        //私有化无参构造
        private Lazy(){}
    
        //返回类实例
        public static Lazy getInstance(){
            if (lazy==null){
                lazy = new Lazy();
            }
            return lazy;
        }
    }
    
  • 但是这种方式线程不安全,在多线程环境下不能正常工作,可以使用synchronized进行加锁,使得线程安全

    //使用双重检测加锁的方式实现线程安全
    public class LazySafe {
        private static LazySafe lazySafe;
    
        private LazySafe(){}
    
        public static LazySafe getInstance(){
            if (lazySafe == null){
                synchronized (LazySafe.class){
                    if (lazySafe==null){
                        lazySafe = new LazySafe();
                    }
                }
            }
            return lazySafe;
        }
    }
    
  • 上面的方式的实现不是原子性操作,多线程环境中可能出现指令重排的现象,从而导致程序出现问题,这是我们需要加上volatile进行修饰

    • 原子性是一个或某多个操作只能一个线程执行完之后,另一个线程才能开始执行该操作
    • 也就是说这些操作是不可分割的,线程不能在这些操作上交替执行
    public class LazySafe {
        //使用了volatile
        private volatile static LazySafe lazySafe;
    
        private LazySafe(){}
    
        public static LazySafe getInstance(){
            if (lazySafe == null){
                synchronized (LazySafe.class){
                    if (lazySafe==null){
                        lazySafe = new LazySafe();
                    }
                }
            }
            return lazySafe;
        }
    }
    

枚举实现单例

  • 这种方式是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。

  • 不能通过 reflection attack(反射) 来调用私有构造方法。

  • 同时,使用该方式创建得到的单例对象时线程安全的

  • 建议使用该方式创建单例对象

    public enum SingleEnum {
        INSTANCE;
    
        public SingleEnum getInstance(){
            return INSTANCE;
        }
    }
    
posted @ 2020-06-29 22:46  snowfox雪狐  阅读(152)  评论(0编辑  收藏  举报