zoukankan      html  css  js  c++  java
  • 单例模式

    单例模式

    第一种(懒汉,线程不安全)

    public class Singleton{
    	private Singleton{};   //构造函数是私有的
    	private static Singleton instance;  //声明对象是静态的
    	public static Singleton getInstance(){  //通过静态方法来构造对象
    		if(instacne == null){  //判断单例对象是否已经存在
    			instance = new  Singleton();
    		}
    		return instance;
    	}
    
    }
    

    这种写法lazy loading很明显,最重要的是多线程不能正常工作

    第二种(懒汉,线程安全)

    public class Singleton{
    	private Singleton{};   //构造函数是私有的
    	private static Singleton instance;  //声明对象是静态的
    	public static synchronized Singleton getInstance(){  //通过静态方法来构造对象
    		if(instacne == null){  //判断单例对象是否已经存在
    			instance = new  Singleton();
    		}
    		return instance;
    	}
    
    }
    

    这种写法可以在多线程中很好的工作,而且看起来它也具备很好的lazyloading,但效率很低

    第三种(饿汉)

    public class Singleton{
    	private Singleton{};   //构造函数是私有的
    	private static Singleton instance = new Singleton();  //声明对象是静态的
    	public static Singleton getInstance(){  //通过静态方法来构造对象
    		return instance;
    	}
    
    }
    

    这种方法通过类加载机制避免了多线程的同步,不过instance在类加载时就实例化,虽然导致类加载的原因有很多,在单例模式中大多数都是调用getInstance方法,但是不能确定有其他的方式导致类加载,这时候初始化instance显然没有达到lazy loading的效果

    第四种(饿汉)

    public class Singleton{
    	private Singleton instance = null;
    	static{
    	instance = new Singleton()
    	}
    	private Singleton{};   //构造函数是私有的
    	public static  Singleton getInstance(){  //通过静态方法来构造对象
    		return this instance;
    	}
    
    }
    

    第五种(静态内部类)

      public class Singleton {  
          private static class SingletonHolder {  
          private static final Singleton INSTANCE = new Singleton();  
          }  
          private Singleton (){}
          public static final Singleton getInstance() {  
              return SingletonHolder.INSTANCE;  
          }  
      }  
    

    这种方式同样是采用类加载的机制来保证初始化instance时只有一个线程,它跟第三第四种方式不同的是:第三种和第四种方式只要Singleton类被加载了,那么instance就会被实例化,而这种方式是Singleton类被加载了,instance不一定会被实例化,因为SingletonHoder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance.

    第六种(枚举)

      public class Singleton {  
         INSTANCE;
    	 public void whateverMathod(){
       }
    }  
    

    这种方式能避免多线程的同步,而且能防止凡序列化重新创建新的对象,不过用的人不多

    第六种(枚举)

    public class Singleton {  
        private Singleton() {}                     //关键点0:构造函数是私有的
        private static Singleton single = null;    //关键点1:声明单例对象是静态的
        private static object obj= new object();
        public static Singleton GetInstance()      //通过静态方法来构造对象
        {                        
             if (single == null)                   //关键点2:判断单例对象是否已经被构造
             {                             
                lock(obj)                          //关键点3:加线程锁
                {
                   if(single == null)              //关键点4:二次判断单例是否已经被构造
                   {
                      single = new Singleton();  
                    }
                 }
             }    
            return single;  
        }  
    }
    

    有时候由于延迟加载或者缓存的问题,以判断关键点2是不能保证是否只创建了一个单例,所以需要在线程锁之后判断一次

    单例是为了保证系统中只有一个实例,其关键点有4

    1 私有构造函数

    2 声明静态单例对象

    3.构造单例对象之前要加锁(lock一个静态的object对象)

    4.需要两次检测单例实例是否已经被构造,分别在锁之前和锁之后

    补充问题:

    1.为何要检测两次?

    如上面所述,有可能延迟加载或者缓存原因,造成构造多个实例,违反了单例的初衷。

    2.构造函数能否公有化?

    不行,单例类的构造函数必须私有化,单例类不能被实例化,单例实例只能静态调用

    3.lock住的对象为什么要是object对象,可以是int吗?

    不行,锁住的必须是个引用类型。如果锁值类型,每个不同的线程在声明的时候值类型变量的地址都不一样,那么上个线程锁住的东西下个线程进来会认为根本没锁,相当于每次都锁了不同的门,没有任何卵用。而引用类型的变量地址是相同的,每个线程进来判断锁多想是否被锁的时候都是判断同一个地址,相当于是锁在通一扇门,起到了锁的作用。

  • 相关阅读:
    快速创建jsp页面的方法
    Webstorm的一些常用快捷键
    eclipse 怎么在new菜单里添加JSP file选项?
    人生最重要的时候,从30岁到35岁:为生命多积累一些厚度
    android 生命周期四代码
    android WebView onJsAler onJsC…
    android java js 回调 真心好用
    linux下dlopen的使用
    android ndk jni 实例1
    android 退出程序 结束线程
  • 原文地址:https://www.cnblogs.com/zddsblog/p/7465926.html
Copyright © 2011-2022 走看看