首页 > 代码库 > 单利模式

单利模式

菜鸟编写后台代码的时候,应为前台通过ajax与后台交互,所以后台通过Map与前台通信,每次都使用Map,因此考虑到建立一个单例的Map,在一个Controller中使用。(在整个后台都使用一个Map好像不合适,后台有多个功能,每个功能都有可能被用到)

单例模式有一下几类:

1、懒汉模式:

  在使用的地方创建对象,起到延时加载的作用,但是容易产生线程安全的问题。

2、饿汉模式

  在类创建的同时已经创建了一个静态变量供使用(一开始就亟不可待的创建了对象,饿汉比较形象的表面了这一点),因此不存在线程安全的问题。

 

懒汉模式:

懒汉模式又有几个分类

线程不安全的懒汉模式:

public class Single{        private static Single single = null ;    private Sngle(){}    public static Single getSingle(){            if(single == null){                   single = new Single();        }             return single ;    }}

为什么说这是线程不安全的懒汉模式呢?

假设这样的场景:两个线程并发调用初始对象的方法如:getSingle();假设线程一先判断完single是否为null,既代码中的line A进入到line B的位置。刚刚判断完毕后,(并没有对single进行实例化)JVM将CPU资源切换给线程二,由于线程一还没执行line B,所以single仍然是空的,因此线程二执行了new Single()操作。片刻之后,线程一被重新唤醒,它执行的仍然是new Single()操作,好了,问题来了,这样内存就存在连个Single对象,因此单例模式就失去了意义。

为此,我们做了一点改进,解决线程不安全的问题

线程安全懒汉单例模式一:

public class Single{        private static Single single = null ;    private Sngle(){}    public static synchronized Single getSingle(){    //添加了同步锁 synchronized        if(single == null){                   single = new Single();        }             return single ;    }}

比起第一段代码仅仅在方法中多了一个synchronized修饰符,现在可以保证不会出线程问题了。但是这里有个很大(至少耗时比例上很大)的性能问题。除了第一次调用时是执行了Single的构造函数之外,以后的每一次调用都是直接返回single对象。返回对象这个操作耗时是很小的,绝大部分的耗时都用在synchronized修饰符的同步准备上,因此从性能上说很不划算。

 懒汉模式三 线程安全

public class Single{        private static Single single = null ;    private Sngle(){}    public static Single getSingle(){    //添加了同步锁 synchronized
    synchronized (Single.class){   if(single == null){    single = new Single();   }  return single ;   }  }}

这样将synchronized移到代码内部,每次执行getSngle()方法的时候,还是会进行同步synchronized,所以又有另一个方法:

懒汉模式四 线程安全之双重锁定检查

 

public class Single{        private static Single single = null ;    private Sngle(){}    public static Single getSingle(){    //添加了同步锁 synchronized
    if(single == null){
    synchronized (Single.class){   if(single == null){    single = new Single();   }  return single ;   }
    }  }}

这样一来,只有在第一次初始化single对象的时候,才会进行同步锁,其他时候不在进行判断

 

饿汉模式

public class Single{        private static Single single = new Single();    private Sngle(){}    public static Single getSingle(){            if(single == null){                   single = new Single();        }             return single ;    }}

因为饿汉模式在类加载的时候就已经初始化了单例对象,所以不存在线程安全的问题,有利就有弊,如果该对象消耗资源比较多,希望延时加载时饿汉模式可能就无法做到。还有一种情况就是,如果单例对象在实例化时需要通过外部传参,那么饿汉模式也无法完成这一要求。

饿汉模式二

public class Single{        private static Single single = null;
  static{
    single = new Single();
  } private Sngle(){} public static Single getSingle(){ if(single == null){ single = new Single(); }  return single ; }}

与上一种方式差不多,也是在类加载的时候进行实例化。

 

静态内部类方式实现单例模式

public class Single{      private static class InnerClass{
    public static final Single SINGLE = new Single();
  }
public static Single getSingle(){  return InnerClass.SINGLE ; }}

枚举实现单例

 

public enum Single{
  SINGLE;
  public void method(){}
}