定义应用场景单例实现方法饿汉式懒人式双重校验锁枚举类静态内部类单例模式扩展线程唯一单例集群唯一实例多实例模式定义所谓单例是一个类它具有以下特点:只允许创建一个对象,并提供全局访问点。这个对象必须有它自己的类。创建应用场景表示全局唯一的类:序列号生成器,保存某些固定信息(如配置文件、密码等Key)的类,用于处理访问资源时的冲突:类单例的实现方式写法files是在类加载的时候创建一个Singleton对象,也就是需要的时候不创建(不支持Lazyloading)是它最大的问题,容易造成资源浪费(可能性有点大)小的)。publicclassSingleton{//保存这个类的唯一实例privatestaticSingletoninstance=newSingleton();/***private构造函数防止其他类通过new直接创建本类的实例*/privateSingleton(){//什么都不做}/***获取单例的main方法*/publicstaticSingletongetInstance(){返回实例;}}Lazystyle下面是一个最简单的hungrystylesingleton的实现,需要的时候去加载就行了,但是这种写法会出问题。比如线程A调用getInstance,发现instance==null然后执行到位置2(假设此时对象还没有成功new),然后线程B进入find,此时实例为仍然为null,会创建一个新的对象,导致线程A和线程B获取的对象不是同一个对象。这是下面代码在多线程情况下会出现的问题。publicclassSingleton{//保存该类的唯一实例privatestaticSingletoninstance=null;/***private构造函数阻止其他类通过new直接创建该类的实例*/privateSingleton(){//Nothingdo}/***Main方法获取单例*/publicstaticSingletongetInstance(){if(instance==null){//1instance=newSingleton();//2}返回实例;}}上面的问题好像很容易解决→加锁加锁确实解决了上面的问题,但是每次getInstance都会加一个加锁的过程,这个并不完美!于是就有了下面的双重检查锁的实现方法。publicclassSingleton{//保存该类的唯一实例privatestaticSingletoninstance=null;/***私有构造器阻止其他类通过new直接创建本类的实例*/privateSingleton(){//什么都不做}/***获取单例的主要方法*/publicstaticsynchronizedSingletongetInstance(){if(instance==null){//1instance=newSingleton();//2}返回实例;}}doubleChecklock下面是doublechecklock的经典单例实现publicclassSingleton{//保存该类的唯一实例privatestaticSingletoninstance=null;/***private构造器防止通过本类的newInstance直接创建其他类*/privateSingleton(){//什么都不做}/***获取单例的主要方法*/publicstaticSingletongetInstance(){if(null==instance){//操作1:第一次检查synchronized(Singleton.class){//操作2if(null==instance){//操作3:第二次检查instance=newSingleton();//操作4}}}返回实例;首先分析一下为什么操作1和操作2的功能会出现上面的问题,所以在操作3之前加一个操作2可以保证一次只有一个线程执行操作4,但是这样会造成每次调用getInstance()申请/释放锁都会造成很大的性能消耗,所以需要在操作2之前加一个操作1来避免此类问题。另外,static修饰的变量保证只会加载一次。所以看起来这个双重检查锁是完美的?上面的操作4可以分为以下三个子操作objRef=allocate(IncorrectDCLSingletion.class);//子操作1:分配对象所需的存储空间invokeConstructor(objRef);//子操作2:初始化objRef=objRef;引用的对象实例;//子操作3:将对象引用写入共享变量synchronized的临界区允许重新排序,JIT编译器可能会将上述操作重新排序为子操作1→子操作3→子操作2,所以可能会发生的情况是,当一个线程执行重排后的操作4(1→3→2)时,当该线程刚执行完子操作3(子操作2未执行),其他线程执行到操作1,则instance≠null会直接返回,但是这个instance还没有初始化,所以会有问题。如果用volatile关键字修饰实例,就不会出现这种情况。volatile解决了子操作2和子操作3的重排序问题。volatile还可以防止这个共享变量存储在寄存器中,避免可见性问题。枚举类枚举类也可以安全地实现单例模式publicclassEnumSingleton{privateEnumSingleton(){}publicenumInstanceObject{INSTANCE;publicEnumSingletongetInstance(){返回新的EnumSingleton();}}publicstaticEnumSingletongetInstance(){returnInstanceObject.INSTANCE.getInstance();}}静态内部类由于静态变量只有在使用的时候才会初始化,所以Singleton实例只会在1执行的时候创建。另外,静态内部类的加载是在程序中调用静态内部类时加载的,与外部类的加载没有必然关系。publicclassSingleton{/***private构造函数阻止其他类通过new*/privateSingleton(){//什么都不做}privatestaticclassSingletonHolder{privatestaticSingletoninstance=newSingleton();}/***获取单例的主要方法*/publicstaticsynchronizedSingletongetInstance(){returnSingletonHolder.instance;//1}}以上是内部静态类的实现,调用时会加载InstanceHolderso这也是一个惰性单例。单例模式扩展了线程的唯一单例。这个单例就是每个线程只能创建一个唯一的对象,可以创建一个k-v容器来存放对象和线程的关系。下面的代码实现了饿了么形式的只线程单例。publicclassThreadSingleton{//类变量privatestaticMap
