设计模式系统回顾(3)单例模式

其目的在于一个类在任何情况下只有一个实例

1.饿汉式单例

类在被加载的时候初始化

public class HungrySingleton {
    private static final HungrySingleton hungrySigleton = new HungrySingleton();
	//将单例对象的构造器私有化,无法直接通过 new 来创建对象,只能通过我们提供的 getInstance 方法来获得单例对象
    private HungrySingleton() {
    }

    public static HungrySingleton getInstance(){
        return hungrySigleton;
    }
}

//第二种 静态代码块的方式
public class HungryStaticSingleton {
    private static final HungryStaticSingleton hungrySigleton;

    static {
        hungrySigleton = new HungryStaticSingleton();
    }

    private HungryStaticSingleton() {
    }

    public static HungryStaticSingleton getInstance(){
        return hungrySigleton;
    }
}

优点:
创建对象没有加锁、执行效率比较高
缺点
浪费内存

2.懒汉式单例

被使用时才会初始化

//第一种,线程不安全
public class LazySingleton {
	//开始只是赋了一个 null 值,并没有进行初始化,调用 getInstance 方法的时候才会去初始化单例对象
    private static LazySingleton lazySingleton = null;

    private LazySingleton() {
    }

    public static LazySingleton getInstance(){
        if(null == lazySingleton){//为空则说明第一次获取单例对象,进行初始化
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;//不为空则说明已经初始化了,直接返回
    }
}

//第二种,线程安全,加锁
public class LazySyncSingleton {
    private static LazySyncSingleton lazySingleton = null;

    private LazySyncSingleton() {
    }

    public synchronized static LazySyncSingleton getInstance(){
        if(null == lazySingleton){
            lazySingleton = new LazySyncSingleton();
        }
        return lazySingleton;
    }
}


//第三种,线程安全,双空判断(双重锁)
//一个是 lazySingleton 属性上加了 volatile 关键字来修饰,原因就是解决多线程下的可见性问题,因为我们的 getInstance 方法在判断 lazySingleton是否为 null 时候并没有加锁,所以假如线程 t1 初始化过了对象,另外线程如 t2 是无法感知的,而加上了 volatile 就可以感知到。同时volatile 可以禁止指令重排序
//另一个改变就是把 synchronized 关键字移到了方法内部,尽可能缩小加锁的代码块,提升效率
public class LazyDoubleCheckSingleton {
    private volatile static LazyDoubleCheckSingleton lazySingleton = null;

    private LazyDoubleCheckSingleton() {
    }

    public static LazyDoubleCheckSingleton getInstance(){
        if(null == lazySingleton){
            synchronized (LazyDoubleCheckSingleton.class){
                if(null == lazySingleton){
                    lazySingleton = new LazyDoubleCheckSingleton();
                }
            }
        }
        return lazySingleton;
    }
}

//第四种  内部懒汉,不过不能防反射
public class LazyInnerClassSingleton {

    private LazyInnerClassSingleton(){
    }

    public static final LazyInnerClassSingleton getInstance(){
        return InnerLazy.LAZY;
    }

    private static class InnerLazy{
        private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
    }
}

//第五种 防止反射破坏的内部懒汉,不能防序列化
public class LazyInnerClassSingleton {

    private LazyInnerClassSingleton(){
        //防止反射破坏单例
         if(null != InnerLazy.LAZY){
           throw new RuntimeException("不允许通过反射类构造单例对象");
         }
    }

    public static final LazyInnerClassSingleton getInstance(){
        return InnerLazy.LAZY;
    }

    private static class InnerLazy{
        private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
    }
}


//第六种 防止反射破坏,防止序列化破坏的内部懒汉
public class LazyInnerClassSingleton implements Serializable {

    private LazyInnerClassSingleton(){
        //防止反射破坏单例
         if(null != InnerLazy.LAZY){
           throw new RuntimeException("不允许通过反射类构造单例对象");
         }
    }

    public static final LazyInnerClassSingleton getInstance(){
        return InnerLazy.LAZY;
    }

    private static class InnerLazy {
        private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
    }

    private Object readResolve(){
        return InnerLazy.LAZY;
    }
}

3.注册式单例

将每一个实例都保存起来,然后在需要使用的时候直接通过唯一的标识获取实例


public class ContainerSingleton {
    private ContainerSingleton(){
    }

    private static Map<String,Object> ioc = new ConcurrentHashMap<>();//存储单例对象

    public static Object getBean(String className){
        synchronized (ioc){
            if(!ioc.containsKey(className)){//如果容器中不存在当前对象
                Object obj = null;
                try {
                    obj = Class.forName(className).newInstance();
                    ioc.put(className,obj);//将className作为唯一标识存入容器
                }catch (Exception e){
                    e.printStackTrace();
                }
                return obj;
            }
            return ioc.get(className);//如果容器中已经存在了单例对象,则直接返回
        }
    }
}

public class MyObject {
}


public class TestContainerSingleton {
    public static void main(String[] args) {
        MyObject myObject1 = (MyObject) ContainerSingleton.getBean("package.MyObject");
        MyObject myObject2 = (MyObject) ContainerSingleton.getBean("package.MyObject");

        System.out.println(myObject1 == myObject2);//输出:true // true 是因为我们加了 synchronized 关键字,实际上 Spring 框架中用的就是容器式单例,默认是线程不安全的。
    } 
}

4.枚举式

一种优雅的写法

public class MyObject {
}

public enum EnumSingleton {
    INSTANCE;

    private MyObject myObject;

    EnumSingleton() {
        this.myObject = new MyObject();
    }

    public Object getData() {
        return myObject;
    }

    public static EnumSingleton getInstance(){
        return INSTANCE;
    }
}

public class TestEnumSingleton {
    public static void main(String[] args) throws Exception{
        EnumSingleton enumSingleton = EnumSingleton.getInstance();
        System.out.println(enumSingleton.getData() == enumSingleton.getData());//输出:true
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值