首页 > 其他 > 详细

设计模式之单例模式,如何破坏单例以及怎么防止

时间:2020-04-15 20:18:54      阅读:68      评论:0      收藏:0      [点我收藏+]
  • 基础概念

单例模式就是只需要创建一次,在整个应用生命周期都可以一直使用。

我们常分为饿汉式和懒汉式两种。

饿汉式

饿汉式是在初始化的时候就将单例对象创建出来。通常,通过属性new创建自身。该方式不存在线程安全的问题(JVM保证线程安全),但会造成内存资源的浪费。

我们可以创建一个这样的类:

1、定义私有化的成员变量:需初始化,用static修饰。

2、私有化构造器,防止其被其他类new。

3、对外提供公共方法,返回获取创建好的单例对象,用static修饰。

public class Singleton {

    // 私有化的成员变量:需初始化
    private static Singleton singleton = new Singleton();
    
    // 私有化构造器,防止其被其他类new
    private Singleton() {
        
    }
    
    // 对外提供公共方法,返回获取创建好的单例对象
    public static Singleton getInstance() {
        
        return singleton;
    }
    
    public void otherMethod() {
        System.out.print("其他的行为方法");
    }
}

 

  • 懒汉式

懒汉式是在第一次使用的时候,才将单例对象创建出来。该方式存在线程安全的问题,但不会造成内存资源的浪费。

我们可以创建一个这样的类:

1、定义私有化的成员变量:无需初始化,用static修饰。

2、私有化构造器,防止其被其他类new。

3、对外提供公共方法,返回获取创建好的单例对象。只有当不存在时候才new,存在则直接返回,用static修饰。

public class Singleton {

    // 私有化的成员变量:不做初始化
    private static Singleton singleton = null;
    
    // 私有化构造器,防止其被其他类new
    private Singleton() {
        
    }
    
    // 对外提供公共方法,返回获取创建好的单例对象
    public static Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
    
    public void otherMethod() {
        System.out.print("其他的行为方法");
    }
}

懒汉式,怎么解决线程安全问题呢?

  • 双重检查锁

两个线程同时访问的时候,我们可以加锁处理。

1、私有化的成员变量:不做初始化,volatile 保证原子性。

2、私有化构造器,防止其被其他类new。

3、对外提供公共方法,返回获取创建好的单例对象。加两层非空校验,将第二层校验为null的代码块用synchronized同步代码块。

public class Singleton {

    // 私有化的成员变量:不做初始化
    private volatile static Singleton singleton = null;
    
    // 私有化构造器,防止其被其他类new
    private Singleton() {
        
    }
    
    // 对外提供公共方法,返回获取创建好的单例对象
    public static Singleton getInstance() {
        // 第一层非空校验
        if (singleton == null) {
            // 加同步锁,保证只有一个线程进入
            synchronized (Singleton.class) {
                // 第二层非空校验,防止在第一次非空校验时,两个线程拿到的都是null对象而创建两次。
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
    
    public void otherMethod() {
        System.out.print("其他的行为方法");
    }
}

可以了解下对象在JVM中的创建步骤。以及线程相关知识点,同步,怎么保证原子性等。

  • 静态内部类

1、私有化构造器,防止其被其他类new。

2、使用内部类(JVM保证),创建单例对象。

3、对外提供公共方法,通过调用内部类的属性,返回获取的创建好的单例对象。

public class StaticSingleton {
    
    // 私有化构造器,防止其被其他类new
    private StaticSingleton() {
        
    }
    
    // 使用内部类(JVM保证),创建单例对象
    private static class SingletonFactory {
        private static StaticSingleton singleton = new StaticSingleton();
    }
    
    // 对外提供公共方法,通过调用内部类的属性,返回获取的创建好的单例对象
    public static StaticSingleton getInstance() {
        
        return SingletonFactory.singleton;
    }
    
    public void otherMethod() {
        System.out.print("其他的行为方法");
    }
}

 

  • 枚举
public enum SingletonEnum {

    INSTANCE;
    
    public void otherMethod() {
        System.out.print("其他的行为方法");
    }
}

 

问题:如何破坏单例?

1.反射,通过反射获取单例对象的构造器,暴力破解后即可创建多个不同实例。怎么防止:禁止通过反射会创建对象。

2.序列化,通过深克隆复制对象,可生成多个实例。怎么防止:重写在单例对象中readObject()方法。

 

设计模式之单例模式,如何破坏单例以及怎么防止

原文:https://www.cnblogs.com/scorpio-cat/p/12707402.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!