单例模式

一、定义

设计模式:一种设计思想,针对不同的业务场景,用不同的方式去设计代码结构,其最最本质的目的是为了解耦,延伸一点的话,还有为了可扩展性和健壮性,但是这都是建立在解耦的基础之上。

单例模式是一种常用的软件设计模式,单例对象的类必须保证只有一个实例存在。保证一个类仅有一个实例,并提供一个访问他的全局访问点,该实例被所有程序模块共享。

二、单例模式构造

public class Singleton {  
    private Singleton() {}                     //关键点0:构造函数是私有的
    private static Singleton single = null;    //关键点1:声明单例对象是静态的
    private static object obj= new object();
    public static Singleton GetInstance()      //通过静态方法来构造对象
    {                        
         if (single == null)                   //关键点2:判断单例对象是否已经被构造
         {                             
            lock(obj)                          //关键点3:加线程锁
            {
               if(single == null)              //关键点4:二次判断单例是否已经被构造
               {
                  single = new Singleton();  
                }
             }
         }    
        return single;  
    }  
}

关键点0/1:私有的构造函数保证该类不能在外面定义类的对象,单例类不能被实例化,单例实例只能静态调

关键点2/4:检测两次单例是否被构造,原因是,有可能延迟加载或者缓存原因,造成构造多个实例,违反了单例的初衷。

关键点3:   保证线程安全,锁住的必须是个引用类型,如果锁是值类型(如int),每个不同的线程在声明的时候值类型变量的地址都不一样,那么上个线程锁住的东西下个线程进来会认为根本没锁,相当于每次都锁了不同的门。而引用类型的变量地址是相同的,每个线程进来判断是否被锁的时候都是判断同一个地址,相当于是锁在同一扇门,起到了锁的作用。


三、单例模式优缺点:

优点:

   1.在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就防止其它对象对自己的实例化,确保所有的对象都访问一个实例 。

   2.单例模式具有一定的伸缩性,类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性。 

   3.提供了对唯一实例的受控访问。 
   4.由于在系统内存中只存在一个对象,因此可以 节约系统资源,当 需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。 
   5.允许可变数目的实例。 

   6.避免对共享资源的多重占用。

缺点:

    1.不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。 
    2.由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。 
    3.单例类的职责过重,在一定程度上违背了“单一职责原则”。 

    4.滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。 

四、两种模式:

 1、饿汉式:预先加载,单例实例在类装载时就构建。

public class Test {
        private Test() {
        }
        public static Test instance = new Test();
        public Test getInstance() {
                return instance;
        }
}

优点:①线程安全    ②在类加载的同时已经创建好一个静态对象,调用时反应速度快

缺点:资源效率不高,可能getInstance()永远不会执行到,但执行该类的其他静态方法或者加载了该类 


2、懒汉式:单例实例在第一次被使用时构建,延迟初始化。 

class Test {
        private Test() {
        }
        public static Test instance = null;
        public static Test getInstance() {
                if (instance == null) {  //多个线程判断instance都为null时,在执行new操作时多线程会出现重复情况
                        instance = new Singleton2();
                }
                return instance;
        }
}

优点: 避免了饿汉式的那种在没有用到的情况下创建事例,资源利用率高,不执行getInstance()就不会被实例,可以执行该类的其他静态方法。

缺点:懒汉式在单个线程中没有问题,但多个线程同时访问的时候就可能同时创建多个实例,而且这多个实例不是同一个对象,虽然后面创建的实例会覆盖先创建的实例,但是还是会存在拿到不同对象的情况。解决这个问题的办法就是加锁synchonized,第一次加载时不够快,多线程使用不必要的同步开销大。 

3、双重检验:懒汉式+同步锁+检验

class Test {
        private Test() {
        }
        public static Test instance = null;

        public static Test getInstance() {
                if (instance == null) {                           //第一次检验
                        synchronized (Test.class) {               //锁
                                if (instance == null) {           //第二次检验
                                        instance = new Test();    //实例化
                                }
                        }
                }
                return instance;
        }
}
优点: 资源利用率高,不执行getInstance()就不被实例,可以执行该类其他静态方法 

缺点: 第一次加载时反应不快,由于java内存模型一些原因偶尔失败

4、静态内部类:

class Test {
        private Test() {
        }

        private static class SingletonHelp {
                static Test instance = new Test();
        }

        public static Test getInstance() {
                return SingletonHelp.instance;
        }
}
优点: 资源利用率高,不执行getInstance()不被实例,可以执行该类其他静态方法 

缺点: 第一次加载时反应不够快


一般采用饿汉式,若对资源十分在意可以采用静态内部类,不建议采用懒汉式及双重检测

来源:

1、单例模式的优缺点和使用场景

2、面试被问设计模式?不要怕看这里:单例模式

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值