设计模式-单例模式

单例模式就是一个类只有一个实例存在,即唯一实例

当创建一个对象需要消耗很多资源的时候,就可以使用单例模式来减少资源的消耗

单例模式可以分为两种:饿汉式,懒汉式

先了解饿汉式再了解懒汉式这样的学习顺序比较好,因为饿汉式直接返回对象比较简单

懒汉式就是不愿意创建实例对象,只有等getInstance()方法被调用的时候才创建对象,并返回

饿汉式就是老早就创建好了实例对象,调用getInstance()方法的时候,不用再创建,直接返回

总之:直接返回就是饿汉式,懒汉式则需要先创建,再返回

注意:下面举的例子构造方法都是private,这样就不能通过A a=new A()的方式进行实例化,而是必须通过A a=A.getInstance()的方式进行实例化

懒汉式存在的场景:有些对象创建的开销是比较大的,你如果一开始就创建出来,后面又没有使用,那很浪费
 

懒汉式的一种经典实现:双重检查锁

class A
{
   //属性是这个类的对象
   //而且这个属性必须是私有的
   //这里必须使用volatile关键字,保证原子性
   private volatile static A a;
  
   //构造方法必须是私有的
   private A()
   {
    

   }

  //创建一个方法来获取这个对象 
  //加锁来防止被多次实例化
   public synchronized static A getInstance()
   {
      //第一次使用的时候进行实例化,即第一次调用getInstance方法的时候进行实例化
      if(a==null)
      {
         synchronized(A.class)
         {
           if(a==null)//第二次判断a对象是否为空
           {
             a=new A();
           }
         }
      }
      return a;
   }
}

为什么要双重校验:

假设不双重校验:

 public synchronized static A getInstance()
   {
      //第一次使用的时候进行实例化,即第一次调用getInstance方法的时候进行实例化
      if(a==null)
      {
         synchronized(A.class)
         {
              a=new A();
         }      
      }
      return a;
   }

假设两个线程一起调用了getInstance()方法,并且都发现singleton这个Singleton对象没有被创建出来,然后第一个线程获取了锁,创建了一个Singleton对象singleton,创建完这个对象之后就释放了锁,第二个线程拿到锁之后,会再创建一个Singleton对象,这样就创建了两个对象

所以,需要在拿到锁之后,再判断一下,这个A对象是否已经被创建出来了,如果被创建出来了,就不用再创建

单例模式的问题:全局共享一个变量,相当于全局变量,程序到处都可以更改

常见面试题:手写单例模式

由于在常用的设计模式中,单例模式是唯一能用短短几十行代码就能完整实现的模式,因此手写一个单例模式是一道很常见的面试题(多线程下的单例模式)

饿汉式:

class SinglePattern
{
    static SinglePattern  singlePattern=new SinglePattern();
    private SinglePattern()
    {

    }
    public static SinglePattern getInstanceOf()
    {
        return singlePattern;
    }
}

public class test
{
    public static void main(String[] args){
        SinglePattern singlePattern=SinglePattern.getInstanceOf();
        System.out.println(singlePattern);
    }
}

懒汉式:

class SinglePattern
{
    static SinglePattern  singlePattern;
    private SinglePattern()
    {

    }
    public static SinglePattern getInstanceOf()
    {
        if(singlePattern==null)
        {
           singlePattern=new SinglePattern();
           return singlePattern;
        }
    }
}

public class test
{
    public static void main(String[] args){
        SinglePattern singlePattern=SinglePattern.getInstanceOf();
        System.out.println(singlePattern);
    }
}

懒汉式不是线程安全的,因为,有可能两个线程都执行完if(singlePattern==null),发现没有创建对象,于是都创建对象,这样就没有达到单例的效果

如果在getInstanceOf方法上加synchronized,变成:

  public static synchronized SinglePattern getInstanceOf()
    {
        if(singlePattern==null)
        {
           singlePattern=new SinglePattern();
           return singlePattern;
        }
    }

确实可以保证只有一个线程进入getInstanceOf方法,但是又会出现新的问题:我们只是想创建对象的时候保证单线程进入,获取对象的时候其实是允许多线程同时获得这个对象的,所以这种做法是不可取的

加锁双重校验:

 public static synchronized SinglePattern getInstanceOf()
    {
        if(singlePattern==null)
        {
           synchronized(SinglePattern.class)
           {
               if(singleton==null)
               {
                   singlePattern=new SinglePattern();
               }                
           }
        }
        return singlePattern;
    }

两次判断对象是否被创建出来,拿到锁之后再判断一次对象是否被创建出来了,没有被创建才需要去创建

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值