• java设计模式学习-单例模式


        java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”单例模式可以保证一个应用中有且只有一个实例,避免了资源的浪费和多个实例多次调用导致出错。

      单例模式有以下特点:
      1、单例类只能有一个实例。
      2、单例类必须自己创建自己的唯一实例。
      3、单例类必须给所有其他对象提供这一实例。

      所以相应的,我们用代码实现为:

      1.私有化该类的构造函数

      2.通过new在本类中创建一个本类对象

      3.提供一个共有的方法,给给类创建的对象返回

     1. 饿汉式写法

    public class Singleton { //饿汉式
         int a=1;
         private Singleton(){};
         private static Singleton instance = new Singleton();
         public static Singleton getInstance(){
             return instance;
         }
    调用方法:Singleton instance = Singleton.getInstance();

    优点:饿汉式写法能保证线程安全,而且实现简单

    缺点:在类加载的时候就完成了实例化,会造成内存浪费(可以忽略不计)

      2.懒汉式(线程不安全,不可用)

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

    因为只有在调用getInstance()这个方法的时候,才会去初始化这个单例,所以称为懒汉式

    懒汉式存在线程安全问题,当2个或多个线程同时调用getInstance()方法时,有可能发生如下情况:当第一个线程在执行 if(instance==null)判断的时候,因为此时instance为空,他将会执行instance=new Singleton()来实例化对象,而第二个进程也同时进入了 if(instance==null)的判断,他可能会在第一个线程没有实例化之前进行判断,此时instance依旧为空,于是就实例化了2个Singleton对象,违背了单例模式。

    于是,就有了懒汉式的双重校验锁

    即加锁并且2次判断instance是否为空

    
    
    public class Singleton {
    private static volatile Singleton singleton = null;

    private Singleton() {
    }

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

    2次if(instance == null)校验,确保了线程安全,延迟加载,效率较高

    volatile关键字禁止JVM对指令进行重排序,因为

    singleton = new Singleton();是非原子性操作,原来的流程为先在栈中开辟空间存放singleton的引用,然后在堆中开辟空间存放实例化后的对象,栈中的引用指向堆中的new出来的地址
    。JVM的优化会导致1、先在栈中开辟空间存放singleton的引用,2、然后堆中开辟空间后,3、引用指向堆中的空间,4、再进行实例化。此时在3之后,instance已经不为空,导致其他线程得到的可能是未实例化后的对象。

    内部类

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

    和饿汉式类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同

    的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用,而静态内部类方式在Singleton类被装载时

    并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonHolder类,从而完成Singleton的实例化。

    类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是

    无法进入的。

    优点:避免了线程不安全,延迟加载,效率高。

     
    参考博客:
    
    
    http://blog.csdn.net/dmk877/article/details/50311791
    
    

    
    
    
    


           

  • 相关阅读:
    编写一个程序的步骤
    vue实现瀑布流
    Vue 解决动态生成列表点击事件无效的问题
    筛选分类列表展示
    php实现类似慕课网,php中文网的分类功能
    在一个页面修改数据,并且ajax刷新数据列表的数据实现。
    记账小程序系统简单规划
    茶叶项目---产品的规格添加
    茶叶商城开发
    后端图片上传
  • 原文地址:https://www.cnblogs.com/jinghuyue/p/7069248.html
Copyright © 2020-2023  润新知