单例模式(全7种实现方式)

一、什么是单例模式

    在整个系统中,一个类型只有一个实例,对JAVA来说:一个类只能被实例化一次

一、什么时候使用单例模式

    1.单例模式可以控制资源达到节约资源的目的

    2.单例模式可以做多线程之间的通信

    基于以上两点:可以想到平时用的数据库连接池,线程池都常采用单例模式

三、如何实现单例模式(JAVA)

    普通类:私有静态成员变量、私有构造函数、公有返回实例函数

    枚举类:天生特性就满足单例模式

    1.懒汉模式

        public class CarToolLazy implements CarTool{
            private static final CarTool ct ;
            private CarToolLazy(){}
            public static CarTool getInstance(){
                if(ct==null){
                    ct = new CarToolLazy();
                }
                return ct;
            }
        }

    优点:需要对象时,才会被实例化

    缺点:存在线程安全问题,线程1在if(ct==null)执行完时,失去CPU资源,线程2得到CPU资源实例化了对象,线程1得到资源,也实例化了对象,此时就存在多个对象,违反了单例模式的原则

    2.饿汉模式

        public class CarToolHungry implements CarTool{
            private static final CarTool ct = new CarToolHungry();
            private CarToolHungry(){}
            public static CarTool getInstance(){
                return ct;
            }
        }

    优点:线程安全

    缺点:因为在类加载的时候就实例化了对象,如果此对象很少用、根本没用、很晚才用、那对资源是一种浪费,且会增加类加载的时长(如果实例化这个对象需要做很多消耗资源或者等待资源的时候)

    注:类加载动作是原子的,不能被打断

    3.懒汉模式变种

        public class CarToolLazyNew implements CarTool{
            private static class singleTonUtil{
                public static final CarTool ct= new CarToolLazyNew();
            }
            
            private CarToolLazyNew(){}
            
            public static CarTool getInstance(){
                return singleTonUtil.ct;
            }
        }

    优点:线程安全,在对象需要时实例化

    缺点:无

    注:此方式利用了静态内部类实现,类加载时不会去实例化内部类的成员变量,只有当调用getInstance()方法时才会实例化对象。

    4.饿汉模式变种

        public class CarToolHungryNew implements CarTool{
            private static final CarTool ct ;
            static{
                ct = new CarToolHungryNew();
            }
            private CarToolHungryNew(){}
            public static CarTool getInstance(){
                return ct;
            }
        }

    优点:线程安全

    缺点:因为在类加载的时候就实例化了对象,如果此对象很少用、根本没用、很晚才用、那对资源是一种浪费,且会增加类加载的时长(如果实例化这个对象需要做很多消耗资源或者等待资源的时候)

    注:这种实现方式和饿汉模式没有本质区别,只是把对象的初始化放在了静态代码块中。依然是利用类加载动作是原子的,不能被打断特性,做到线程安全

    5.双重检查

        public class CarToolSynDouble implements CarTool{
            //如果不用volatile变量会导致实例化之后,另外的线程并不能看见实例化
            private volatile static CarTool ct ;
            private CarToolSynDouble(){}
            public static CarTool getInstance(){
                if(ct==null){
                    synchronized (CarToolSynDouble.class) {
                        if(ct==null){
                            ct = new CarToolSynDouble();
                        }
                    }
                }
                return ct;
            }
        }

    优点:线程安全,需要时实例化对象

    缺点:代码复杂

    注:利用双重if(ct==null)判断,加同步原语,加volatile变量实现线程安全,至于为什么使用volatile变量,可以对volatile关键字做深入了解,本质原因就是JAVA内存模型中线程私有内存与主内存的同步知识点,有的同学在使用双重检查的时候没有加volatile修饰,则依然会出现多个实例的情况

    6.使用同步方法

        public class CarToolSyn implements CarTool{
            private static CarTool ct ;
            private CarToolSyn(){}
            public static synchronized CarTool getInstance(){
                if(ct==null){
                    ct = new CarToolSyn();
                }
                return ct;
            }
        }

    优点:线程安全

    缺点:锁资源竞争严重,效率低

    7.使用枚举类

        public enum CarToolEnum {
            instance;
            private CarTool ctie;
            private CarToolEnum(){
                ctie = new CarToolImplEnum();
            }
            public CarTool getInstance(){
                return ctie;
            }
        }
        class CarToolImplEnum implements CarTool{}

    优点:线程安全,为了线程安全不用写额外代码做控制

    缺点:无

    注:利用枚举类型实例本身就是唯一的特性,简单实现单例模式

转载于:https://my.oschina.net/u/3049601/blog/908295

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值