java technology --- Unit / Mode Example

1. Make sure that only one instance of a class, instantiate their own systems to provide this instance

(1)整个系统只需要拥有一个的全局对象,这样有利于协调系统整体的行为
(2)返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance()
(3)将该类的构造函数定义为私有方法
(4) 所谓单例,指的就是单实例,有且仅有一个类实例,这个单例不应该由人来控制,而应该由代码来限制,强制单例
(5)单例模式应用实例:
    <1>网站的计数器,一般采用单例模式实现,否则难以同步
    <2>应用程序的日志应用,一般都用单例模式实现
    <3>Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源
    <4>数据库连接池的设计/多线程的线程池的设计
    <5> 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统
    <6>HttpApplication 也是单位例的典型应用

Example 2. Single Mode Classification: starving type, lazy, double-testing, static inner classes

1)饿汉式单例模式:
      <1>类加载时实例化一个对象给自己的引用
      <2>单例实例在类装载时就构建,并保存在类中。(预先加载法)
      <3>优点:线程安全;
               在类加载的同时已经创建好一个静态对象,调用时反应速度快 ;
       <4>缺点:资源效率不高,可能getInstance()永远不会执行到,
                但执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化  
            //饿汉式(推荐)
           public class EHanDanli{
             //定义私有的无参构造器,用于单例实例
             private EHanDanli() {}
            //此处定义类变量实例并直接实例化,在类加载的时候就完成了实例化并保存在类中
             public static EHanDanli eh= new EHanDanli();
             //定义公开方法,返回已创建的单例
             public EHanDanli getInstance() {
                 return eh;
             } }2)懒汉式单例模式:线程不安全
       <1>单例实例在第一次被使用时再构建,延迟初始化
       <2>优点:避免了饿汉式的那种在没有用到的情况下创建事例;
                资源利用率高,不执行getInstance()就不会被实例,可以执行该类的其他静态方法
       <3>缺点:在多个线程同事访问的时候就可能同事创建多个实例,而且这多个实例不是同一个对象,
                虽然后面创建的实例会覆盖先创建的实例,但是还是会存在拿到不同对象的情况。
                解决这个问题的办法就是加锁synchonized,第一次加载时不够快,多线程使用不必要的同步开销大  
                会降低性能,同步一个方法可能造成程序执行效率下降100倍。       
           public class LHanDanli {
          //定义私有类变量来存放单例,私有的目的是指外部无法直接获取这个变量,而要使用提供的公共方法来获取
          private static LHanDanli lh = null;
          //定义私有构造器,表示只在类内部使用,亦指单例的实例只能在单例类内部创建
          private LHanDanli(){}
         /**
           * 定义公开的方法来返回该类的实例,需要在第一次使用时生成实例,
           *多个线程判断lh都为null时,在执行new操作时多线程会出现重复情况
           *所以为了线程安全,使用synchronized关键字来确保只会生成单例
          **/
           public static synchronized LHanDanli getInstance(){
              if(lh == null){
               lh = new LHanDanli();}
                  return lh;}3)双重检测 
      <1> 使用双重加锁,保证getInstacne()只在第一次会使用同步    
      <2>优点:资源利用率高,不执行getInstance()就不被实例,可以执行该类其他静态方法 
              volatile关键字确保当变量被初始化成Singleton实例时,多个线程正确的处理变量   
              volatile保证了共享变量的可见性,一个线程对变量的操作其他线程会立马知晓,
              不会出现还未初始化完成就被使用的情况 
      <3>缺点:第一次加载时反应不快,由于java内存模型一些原因偶尔失败 
               Java1.4中JVM虚拟机对于volatile关键字的实现会导致双重检查加锁失败,只能使用Java5或以上的版本
           public class Singleton {
             private volatile static Singleton uniqueInstance;
             private Singleton () {}
             public static Singleton getInstance() {
                if (uniqueInstacne == null) {
                      synchronized (Singleton.class) {
                          if (uniqueInstance == null) {
                               uniqueInstance = new Singleton();
                               }}}
                                 return uniqueInstance; }}4)静态内部类 
      <1>优点:资源利用率高,不执行getInstance()不被实例,可以执行该类其他静态方法
      <2>缺点:第一次加载时反应不够快                                  
           public class Test {
               private Test() {}
               private static class SingletonHelp {
                  static Test instance = new Test();}
               public static Test getInstance() {
                 return SingletonHelp.instance;}}   
 (5)注意:双重检测, 静态内部类
      <1>单例模式实际主要分饿汉/懒汉两种模式
      <2>由于懒汉模式是线程不安全的,所以双重检测, 静态内部类是对懒汉模式线程安全操作
      <3>实际上,双重检测, 静态内部类是对懒汉模式的优化                                                 

3. Summary:

(1)一般采用饿汉式:java中饿汉式性能优于懒汉式,c++中一般使用懒单例模式
(2)若对资源十分在意可以采用静态内部类,不建议采用懒汉式及双重检测
(3)单件模式中多线程情况下重复创建对象问题的处理办法:一般采用双重检测 
(4)单例模式必须具备的3个元素:
    <1>私有静态属性,用于存取类的唯一实例
    <2>公共静态方法,用于提供对该唯一实例的存取访问,如果实例未创建,则创建该实例
    <3>用于限制类再次实例化的方式。通常使用私有构建函数的方式来实现
Published 143 original articles · won praise 10 · views 7501

Guess you like

Origin blog.csdn.net/qq591009234/article/details/104306841