23种设计模式(1)-单例模式

定义java

        单例模式,是一种经常使用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。经过单例模式能够保证系统中一个类只有一个实例。即一个类只有一个对象实例。编程

 

特色设计模式

       一、单例类只能有一个实例。
  二、单例类必须本身本身建立本身的惟一实例。
  三、单例类必须给全部其余对象提供这一实例安全

 

单例模式的要点:服务器

    1,私有的构造方法多线程

    2,指向本身实例的私有静态引用并发

    3,以本身实例为返回值的静态的公有的方法jvm

 

单例模式根据实例化对象时机的不一样分为两种:分布式

        一种是饿汉式单例,一种是懒汉式单例。函数

        饿汉式单例在单例类被加载时候,就实例化一个对象交给本身的引用;而懒汉式在调用取得实例方法的时候才会实例化对象。

代码以下:

 

饿汉式单例

 

public class Singleton {  
    private static Singleton singleton = new Singleton();  
    private Singleton(){}  
    public static Singleton getInstance(){  
        return singleton;  
    }  
}

 

懒汉式单例

 

public class Singleton {      private static Singleton singleton;      private Singleton(){}      public static synchronized Singleton getInstance(){          if(singleton==null){              singleton = new Singleton();          }          return singleton;      }   }  

 

单例模式还有一种比较常见的形式:双重锁的形式

 

public class Singleton{    
   private static volatile Singleton instance=null;    
   private Singleton(){        
   //do something    }    
   public static  Singleton getInstance(){        
       if(instance==null){            
           synchronized(SingletonClass.class){                
               if(instance==null){                    instance=new Singleton();                }            }        }        
   return instance;     } }

 

    这个模式将同步内容下方到if内部,提升了执行的效率,没必要每次获取对象时都进行同步,只有第一次才同步,建立了之后就不必了。
        这种模式中双重判断加同步的方式,比第一个例子中的效率大大提高,由于若是单层if判断,在服务器容许的状况下,假设有一百个线程,耗费的时间为100*(同步判断时间+if判断时间),而若是双重if判断,100的线程能够同时if判断,理论消耗的时间只有一个if判断的时间。

        因此若是面对高并发的状况,并且采用的是懒汉模式,最好的选择就是双重判断加同步的方式。

 

单例模式的优势:

    1,在内存中只有一个对象,节省内存空间。

    2,避免频繁的建立销毁对象,能够提升性能。

    3,避免对共享资源的多重占用。

    4,能够全局访问。

 

单例模式的优势:

    1,扩展困难,因为getInstance静态函数没有办法生成子类的实例。若是要拓展,只有重写那个类。

    2,隐式使用引发类结构不清晰。

    3,致使程序内存泄露的问题。

 

适用场景:

        因为单例模式的以上优势,因此是编程中用的比较多的一种设计模式。如下为使用单例模式的场景:

        1,须要频繁实例化而后销毁的对象。

        2,建立对象时耗时过多或者耗资源过多,但又常常用到的对象。

        3,资源共享的状况下,避免因为资源操做时致使的性能或损耗等

        4,控制资源的状况下,方便资源之间的互相通讯。

 

单例模式注意事项:

        只能使用单例类提供的方法获得单例对象,不要使用反射,不然将会实例化一个新对象。

        不要作断开单例类对象与类中静态引用的危险操做。

        多线程使用单例使用共享资源时,注意线程安全问题。

 

关于Java中单例模式的一些常见问题:

 

单例模式的对象长时间不用会被jvm垃圾收集器收集吗

        除非人为地断开单例中静态引用到单例对象的联接,不然jvm垃圾收集器是不会回收单例对象的。

jvm卸载类的断定条件以下:

        1,该类全部的实例都已经被回收,也就是java堆中不存在该类的任何实例。

        2,加载该类的ClassLoader已经被回收。

        3,该类对应的java.lang.Class对象没有任何地方被引用,没法在任何地方经过反射访问该类的方法。

        只有三个条件都知足,jvm才会在垃圾收集的时候卸载类。显然,单例的类不知足条件一,所以单例类也不会被回收。

 

在一个jvm中会出现多个单例吗

        在分布式系统、多个类加载器、以及序列化的的状况下,会产生多个单例,这一点是无庸置疑的。那么在同一个jvm中,会不会产生单例呢?使用单例提供的getInstance()方法只能获得同一个单例,除非是使用反射方式,将会获得新的单例。

代码以下:

 

Class c = Class.forName(Singleton.class.getName());  
Constructor ct = c.getDeclaredConstructor();  
ct.setAccessible(true);   Singleton singleton = (Singleton)ct.newInstance();

 

这样,每次运行都会产生新的单例对象。因此运用单例模式时,必定注意不要使用反射产生新的单例对象。

 

在getInstance()方法上同步有优点仍是仅同步必要的块更优优点?

        由于锁定仅仅在建立实例时才有意义,而后其余时候实例仅仅是只读访问的,所以只同步必要的块的性能更优,而且是更好的选择。

        缺点:只有在第一次调用的时候,才会出现生成2个对象,才必需要求同步。而一旦singleton 不为null,系统依旧花费同步锁开销,有点得不偿失。

 

单例类能够被继承吗

        根据单例实例构造的时机和方式不一样,单例模式还能够分红几种。但对于这种经过私有化构造函数,静态方法提供实例的单例类而言,是不支持继承的。

        这种模式的单例实现要求每一个具体的单例类自身来维护单例实例和限制多个实例的生成。但能够采用另一种实现单例的思路:登记式单例,来使得单例对继承开放。

 

Java知音公众号推送一些Java必备的知识,让您在闲暇之余巩固一下本身的知识体系 ,扩充一下本身的知识面。快利用琐碎时间给本身充电吧!

相关文章
相关标签/搜索