大话设计模式:单例模式

单例模式是就是在系统运行时,我们希望类生成的对象就一个,类实例化只能时一样,比如线程池、缓存等,我们在系统运行如果缓存或线程池变化,可能会造成系统出现异常,资源过度浪费。

单例模式的定义:

    确保一个类只能有一个实例,并提供一个全局访问点。

单例模式分为两种,一种是不安全的单例模式(我们需要废弃),第二种是线程安全的单例模式。下面列举几种单例模式的实现。

1。饿汉式
2。同步方法-懒汉式
3。同步代码块-懒汉式
4。双重检查锁
5。枚举类
6。静态内部类
7。静态枚举类
---
使用单例模式注意三大条件:
1.私有化构造器,
2.类含有静态私有对象,
3.提供公共静态的方法创建或获取私有对象的值。
---
使用单例
优点:
1.在内存中只有一个实例对象,减少频繁创建销毁对象实例的内存开销;
2.避免对资源的过度占用。
缺点:
没有接口,不能继承,与单一职责原则冲突,一个类只应该关系内部逻辑而不应该关系外部怎样实例化。
使用场景:
1.唯一的序列号
2.WEB中的计数器
3.创建一个对象消耗的资源过多

1. 饿汉式代码

/**
 * 单例模式:饿汉式
 */
public class SingletonDemo01 {

    //类初始化立即加载,由于类加载时完成初始化,线程安全。不用同步快,调用效率高。
    private static SingletonDemo01 instance = new SingletonDemo01();

    private SingletonDemo01() {

    }

    public static SingletonDemo01 getInstance() {
        return instance;
    }
}

2. 懒汉式 同步方法

/**
 * 单例模式:懒汉式线程安全
 */
public class SingletonDemo03 {

    //类初始化延迟加载,方法同步线程安全,调用效率低。
    private static SingletonDemo03 instance = null;

    private SingletonDemo03() {
    }

    public static synchronized SingletonDemo03 getInstance() {

        if (instance == null) {
            instance = new SingletonDemo03();
        }
        return instance;
    }
}

3. 懒汉式同步方法

/**
 * 单例模式:懒汉式双重检查锁
 */
public class SingletonDemo04 {

    //由于编译器优化和JVM内部模型原因,同步块会有问题,会出现问题
    private static SingletonDemo04 instance = null;

    private SingletonDemo04() {

    }

    public static SingletonDemo04 getInstance() {

        if (instance == null) {
            synchronized (SingletonDemo04.class) {
                if (instance == null) {
                    instance = new SingletonDemo04();
                }
            }

        }
        return instance;
    }
}

4.静态内部类

/**
 * 单例模式:静态内部类懒加载
 */
public class SingletonDemo05 {

    //外部没有static属性,不会立即加载对象
    //真正调用getInstance,才会加载内部类
    //高效+安全+延迟加载
    private static class SingletonInstance {
        public static SingletonDemo05 instance = new SingletonDemo05();
    }

    private SingletonDemo05() {

    }

    public static SingletonDemo05 getInstance() {
        return SingletonInstance.instance;
    }
}

5. 枚举类

/**
 * 单例模式:枚举类
 */
public enum SingletonDemo06 {
    //直接用SingletonDemo06.INSTANCE本身代理,代表一个对象
    //避免反射、反序列化,效率高
    //没有懒加载
   INSTANCE;
   Enum ss;
}

6. 枚举类实现懒加载

/**
 * 单例模式:枚举类实现懒加载
 */
public class SingletonDemo08 {

    // 私有构造函数
    private SingletonDemo08() {

    }

    public static SingletonDemo08 getInstance() {
        return Singleton.INSTANCE.getInstance();
    }

    private enum Singleton {
        INSTANCE;

        private SingletonDemo08 singleton;

        // JVM保证这个方法绝对只调用一次
        Singleton() {
            singleton = new SingletonDemo08();
        }

        public SingletonDemo08 getInstance() {
            return singleton;
        }
    }
}

7.解决反射漏铜和序列化漏铜

import java.io.ObjectStreamException;
import java.io.Serializable;

/**
 * 单例模式:解决反射漏铜,通过设置constructor.setAccessible(true);//跳过权限校验,是的创建实例不一致
 *           解决序列化漏铜,readResolve()
 */
public class SingletonDemo07 implements Serializable {

    //类初始化延迟加载,方法同步线程安全,调用效率低。
    private static SingletonDemo07 instance = null;

    private SingletonDemo07() {
        if (instance != null) {//防止通过反射破解单例
            throw new RuntimeException();
        }
    }

    public static synchronized SingletonDemo07 getInstance() {

        if (instance == null) {
            instance = new SingletonDemo07();
        }
        return instance;
    }

    //反序列化时,直接返回此对象,而不生成新对象
    private Object readResolve() throws ObjectStreamException {
        return instance;
    }
}
posted @ 2019-07-06 10:50  i孤独行者  阅读(373)  评论(0编辑  收藏  举报