设计模式- 4单例模式

单例模式

    单例模式是一种对象创建型模式,使用单例模式,可以保证为一个类只生成唯一的一个实例对象。也就是说,在整个程序空间中,该类只存在一个实例对象。
因为在应用系统开发时,我们常常有以下需求:

1、在多个线程之间,比如servlet环境,共享同一个资源或者操作同一个对象。

2、在整个程序空间使用全局变量,共享资源。

3、在大规模系统中,为了性能的考虑,需要节省对象的创建时间等等。

因为单例模式可以保证为一个类只生成唯一的实例对象,所以这些情况,单例模式就派上用场了。

饿汉式:

    在在类加载的时候就立即初始化,并且创建单例对象,不管你用不用,我都先new出来再说,避免了线程安全问题;

public class Person {
    //类加载时就完成了初始化
    private static final Person person = new Person();

    private Person(){}

    public static Person getPerson(){
        return person;
    }
}

优点:没有加任何的锁、执行效率比较高, //在用户体验上来说,比懒汉式更好
缺点:类加载的时候就初始化,不管你用还是不用,我都占着空间 浪费了内存,有可能不用
绝对线程安全,在线程还没出现以前就是实例化了,不可能存在访问安全问题

懒汉式1(线程不安全,但效率高)

public class PersonOne {
    //静态块,公共内存区域
    public static PersonOne personOne = null;

    //构造函数私有化
    private PersonOne(){}

    //调用方法之前,先判断
    //如果没有初始化,将其进行初始化,并且赋值
    //将该实例缓存好
    public static PersonOne getPersonOne(){
        if(personOne == null){
            //多线程下会有 两个线程都会进入这个if里面
            personOne = new PersonOne();
        }
        return personOne;
    }
}

懒汉式2(线程安全,但效率不高)

public class PersonTwo {
    //静态块,公共内存区域
    public static PersonTwo personTwo = null;

    //构造函数私有化
    private PersonTwo(){}

    //调用方法之前,先判断
    //如果没有初始化,将其进行初始化,并且赋值
    //直接加锁同步 然后将该实例缓存好
    public static synchronized PersonTwo getPersonTwo(){
        if(personTwo == null){
            //多线程下会有 两个线程都会进入这个if里面
            personTwo = new PersonTwo();
        }
        return personTwo;
    }
}

懒汉式升级 双重检查加锁(对懒汉式的升级,效率更高)

public class PersonTwo {
    //静态块,公共内存区域
    public static PersonTwo personTwo = null;

    //构造函数私有化
    private PersonTwo(){}

    //调用方法之前,先判断
    //如果没有初始化,将其进行初始化,并且赋值
    //直接加锁同步 然后将该实例缓存好
    public static synchronized PersonTwo getPersonTwo(){
        if(personTwo == null){
            //多线程下会有 两个线程都会进入这个if里面
            personTwo = new PersonTwo();
        }
        return personTwo;
    }
}

饿汉式升级

public class PersonFive {

    private boolean initialized = false;

    private PersonFive(){
        synchronized (PersonFive.class){
            if(initialized == false){
                initialized = !initialized;
            }else{
                throw new RuntimeException("单例模式损坏");
            }
        }
    }

    //static 是为了使单例的空间共享
    //保证这个方法不会被重写,重载
    public static final PersonFive getInstance(){
        //在返回结果以前,一定会先加载内部类
        return LazyHolder.LAZY;
    }

    //默认不加载
    private static class LazyHolder{
        private static final PersonFive LAZY = new PersonFive();
    }
}

注册式单例(Spring中写法)

public class BeanFactory {

    private BeanFactory(){}

    // ConcurrentHashMap 会出现线程不安全的行为
    private static Map<String,Object> ioc = new ConcurrentHashMap<>();

    public static Object getBean(String className){
        // 尽管 containsKey和 put 两个方法都是原子的,但在jvm中并不是将这段代码做为单条指令来执行的
        // 假设连续生成2个一样的map key 为userImpl->com.le.service1和userImpl->com.le.service2
        // map的 containsKey 和 put 方法由线程A和B 同时执行 ,那么有可能会出现A线程还没有把 1 put进去时
        // B线程已经在进行if 的条件判断了,也就是如下的执行顺序:
        /*  A:  map 正在放置为userImpl 进去
            A 被挂起
            B:  执行 map.containsKey(userImpl) 返回false
            B:  将com.le.service2的userImpl放进 map
            A:  将com.le.service1的userImpl 放进 map
            map 中key 为userImpl 的value值 还是为 com.le.service1
            期望的结果是放入com.le.service2
         */
        if(!ioc.containsKey(className)){
            Object obj = null;
            try {
                obj = Class.forName(className).newInstance();
                ioc.put(className,obj);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return obj;
        }else{
            return ioc.get(className);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值