设计模式学习之单例模式

单例模式

单例模式属于创建类型的一种常用的软件设计模式。通过单例模式的方法创建在当前进程中有且只有的一个实例(根据需求不同,也可以是在一个线程中有且只有一个实例)
主要意图:有且只有一个实例
主要解决:类的频繁创建与销毁
使用地点:想要控制实例的数量,节省系统资源
实现单例模式有六种实现方法:

1. 单例模式之饿汉式单例

是否多线程安全:
优点:没有加锁但是线程安全
缺点:浪费内存,容易产生垃圾对象
重点:饿汉式线程安全
线程安全的主要是因为会在声明类的时候就会创建内部私有对象,不会因为多线程而产生多个对象
代码如下:

/**
 * 饿汉式单例模式
 * @author wt
 */
public class SingletonPatternHunger {
    /**内部私有静态对象*/
    private static SingletonPatternHunger singleton = new SingletonPatternHunger();
    /**私有化无参构造方法*/
    private SingletonPatternHunger(){}
    /**获取对象接口*/
    public static SingletonPatternHunger getSingleton() {
        return singleton;
    }
}

2. 单例模式之懒汉式单例

懒汉式单例模式我认为是分为三种,分别是线程不安全的简单懒汉式,线程安全的方法锁懒汉式以及理论上线程安全的双检索懒汉式

2.1 线程不安全的简单懒汉式单例

是否多线程安全:
优点:最基本的实现方法,可以在单线程中实现单例
缺点:多线程不安全
代码:

/**
 * 懒汉式单例模式
 * @author wt
 */

public class SingletonPatternLazy {
    /**先声明静态私有对象*/
    private static SingletonPatternLazy lazy;
    /**静态构造方法*/
    private SingletonPatternLazy(){
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                /**异常信息,建议使用开源的log包来显示异常*/
                e.printStackTrace();
            }
            System.out.println("生成了一次对象");
    }
    /**
     * 简单懒汉式单例获取对象接口
     * 线程不安全
     */
    public static SingletonPatternLazy getLazy1(){
        if (lazy == null) {
        /**判断是否有对象,如果没有就创建对象*/
            lazy = new SingletonPatternLazy();
        }
        return lazy;
    }
}

2.2 线程安全的方法锁懒汉式

是否多线程安全:
优点:第一次调用时才会初始化,避免内存浪费
缺点:每次获取对象都要进锁,影响效率
代码:

/**
 * 懒汉式单例模式
 * @author wt
 */

public class SingletonPatternLazy {
        /**先声明静态私有对象*/
        private static SingletonPatternLazy lazy;
        /**静态构造方法*/
        private SingletonPatternLazy(){
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                /**异常信息,建议使用开源的log包来显示异常*/
                e.printStackTrace();
            }
            System.out.println("生成了一次对象");
        }
   /**
     * 方法锁懒汉式单例获取对象接口
     * 线程安全,但是太影响效率
     */
    public synchronized static SingletonPatternLazy getLazy2(){
        if (lazy == null) {
            /**判断是否有对象,如果没有就创建对象*/
            lazy = new SingletonPatternLazy();
        }
        return lazy;
    }
}

2.3 双检索懒汉式单例模式

双检索单例模式其实也是根据懒汉式单例模式进行的改变
jdk版本:1.5+
是否多线程安全:加上volatile关键字是线程安全的
优点:第一次调用时才会初始化,避免内存浪费。进行了判断,不会每次获取对象实例都进入锁
缺点:需要额外代码才可以实现反序列化和反射
重点:volatile

/**
 * 懒汉式单例模式
 * @author wt
 */

public class SingletonPatternLazy {
    /**
     * 先声明静态私有对象,重点volatile
     * 如果没有这个关键字,那么就不是线程安全的,有几率出现错误
     */
    private volatile static SingletonPatternLazy lazy1;
        /**静态构造方法*/
        private SingletonPatternLazy(){
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                /**异常信息,建议使用开源的log包来显示异常*/
                e.printStackTrace();
            }
            System.out.println("生成了一次对象");
        }
        /**
     * 双检索懒汉式单例获取对象接口
     * 理论上线程安全,但是需要在声明对象时,加上volatile关键字
     */
    public static SingletonPatternLazy getLazy3(){
        if (lazy1 == null) {
            synchronized(SingletonPatternLazy.class){
                if (lazy1 == null){
                    /**判断是否有对象,如果没有就创建对象*/
                    lazy1 = new SingletonPatternLazy();
                }
            }
        }
        return lazy1;
    }
}

3. 静态内部类单利模式

是否多线程安全:
优点:可以有效的实现懒加载
缺点:不能防止反射与序列化的破坏,并且只适用于静态域,如果要在实例域进行延迟加载建议使用双检锁单例
代码:

/**
 * 内部类单例模式
 * @author wt
 */
public class SingletonPatternInner {
    /**私有化构造方法*/
    private SingletonPatternInner(){
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            /**异常信息,建议使用开源的log包来显示异常*/
            e.printStackTrace();
        }
        /**用来测试多线程调用后生成对象的次数*/
        System.out.println("生成了一次对象");
    };
    /**获取内部类中生成的对象*/
    public static SingletonPatternInner getSingleton(){
        return SingletonHolder.Singletonholder;
    }
    /**在内部类中生成对象*/
    private static class SingletonHolder{
        private static final SingletonPatternInner Singletonholder= new SingletonPatternInner();
    }
}

4. 枚举单例

单例模式的最佳实现方法,可以有效的阻止反射和序列化破坏
参考链接(推荐):我做认为讲解枚举最好的博客,里面也包含枚举单例的讲解
jdk版本:1.5+
是否多线程安全:
优点:单例模式的最佳实现方法,可以阻止反射和序列化攻击
缺点:在需要反射调用时会报错
代码:

/**
 * 枚举单例模式
 * @author wt
 */
public enum SingletonPatternEnum {
    /**静态常量对象*/
    INSTANCE;
    /**实验数据*/
    private String name;
    /**获取name*/
    public String getName() {
        return name;
    }
    /**输入name*/
    public void setName(String name) {
        this.name = name;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值