设计模式之单例模式

单例模式分为饿汉模式和懒汉模式,饿汉模式。正如其名,饿,饥不择食,当程序运行,类加载的时候就马上创建,不管此类用不用的到;懒,不到不得已不为之,只有当第一次使用到它的时候,才会创建。

因为饿汉式是类加载的时候创建的,所以是类加载器创建,线程安全的。

懒汉式在并发情况下容易出错,是非线程安全的。

饿汉式 线程安全 类加载时就创建对象

第1种写法:直接初始化,简单易懂

package hx.insist.SingleTon.Hungry;
//饿汉 直接加载 线程安全
//直接初始化
public class Single1 {
    private static final Single1 INSTANCE = new Single1();//自行创建,并且const不可修改
    private Single1(){
    }
    public static Single1 getInstance(){
        return INSTANCE;
    }
}

第2种写法:静态代码块,适合复杂初始化场景

package hx.insist.SingleTon.Hungry;
//静态代码块
public class Single2 {
    private static final Single2 INSTANCE;
    static {
        //复杂初始化
        INSTANCE = new Single2();
    }

    private Single2(){
    }
    public static Single2 getInstance(){
        return INSTANCE;
    }
}

第3种写法:枚举,最简洁,jdk1.5之后出现

package hx.insist.SingleTon.Hungry;
//枚举类型 jdk1.5之后
// 跟Single1是差不多一样  枚举类型构造器全部私有化
public enum Single3 {
    INSTANCE//默认静态 常量  重写toString方法,返回常量对象的名字
}

懒汉式 非线程安全 第一次使用时创建对象

第1种写法:简单易懂

package hx.insist.SingleTon.Slacker;
//懒汉 延迟加载 多线程并发可能会出现问题
public class Single1 {
    private Single1(){}
    private static Single1 INSTANCE;
    public static Single1 getInstance(){
        if (INSTANCE==null){
            INSTANCE = new Single1();
        }
        return INSTANCE;
    }
}

第2种写法:加锁 线程安全 效率不高

package hx.insist.SingleTon.Slacker;
//加锁加if
public class Single2 {
    private Single2(){}

    private static Single2 INSTANCE;

    public static Single2 getInstance(){
        if (INSTANCE==null){//处于性能考虑,第一次初始化的时候才需要加锁
            synchronized (Single2.class){
                if(INSTANCE==null){
                    INSTANCE = new Single2();
                }
            }
        }
        return INSTANCE;//如果不是第一次拿,就直接拿就好了
    }
}

第3种写法:静态内部类 线程安全 推荐

package hx.insist.SingleTon.Slacker;
//静态内部类 懒加载且线程安全
// 因为是在内部类加载和初始化的时候创建的(类加载器加载),所以是线程安全的。
public class Single3 {
    private Single3(){
    }
    private static class Inner{
        private static final Single3 INSTANCE = new Single3();
    }

    public static Single3 getInstance(){
        return Inner.INSTANCE;//静态内部类不随着外部类的加载而加载,只有在此处使用的时候才会去加载,然后创建 new Single3
    }
}

还有一种单例注册表方式

insist,on the road
-------------本文结束感谢您的阅读-------------