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

    Singleton-单例模式是确定整个系统中至多只有一个类的实例

    第一种:饱汉模式

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

    注:

    (1)private Singleton(){}//私有化类的构造函数,表明这个类无法声明实例对象;

    (2)public static Singleton getInstance()...因为私有化了类的构造函数,所以需要提供一个静态的方法提供类的实例;

    (3)private final static Singleton instance = new Singleton();饱汉模式下,当这个类被加载的时候,new Singleton() 这句话就会被执行,就算是getInstance()没有被调用,类也被初始化了。这种方式不太好的地方就在于,我们只是希望在真正调用getInstance()方法的时候返回类的对象,而不是依赖于类加载器。

    第二种:饥汉模式

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

    注:

    (1)在方法getInstance()加synchronized控制可以帮我们控制线程同步,但是这样每个线程都要排队来获取,而且哪怕是第一个线程已经把对象创建好了也需要逐个获取类对象,会很影响性能。

    (2)改版一,进行Double-Check
    public class Singleton{
        private Singleton(){}
        private static Singleton instance = null;
        public static Singleton getInstance() {
            if(instance == null) {
                synchronized(Singleton.class) {
                    if(instance == null) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }

    这样的流程是:

      (1)如果实例创建了,则不需要同步直接返回实例;

      (2)如果不存在,则同步线程进行创建;

      (3)返回。

    但是这样实现的问题就在于:singleton = new Singleton();,因为创建一个类的实例并不是原子操作的,JVM需要:

      (1)分配内存空间;

      (2)进行类的实例化;

      (3)实例对象指向内存地址,返回(只有返回之后,对象instance才不是null,所以这样就还是会存在问题)

    (3)改版二

      将instance声明为volatile,因为被volatile修饰的对象不会在多个线程中同时存在,而是直接从内存中读取。使用volatile关键字声明的变量或对象通常拥有和优化和(或)多线程相关的特殊属性。volatile参考文献

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

     第三种:枚举

    public enum Singleton {
      instance;  
    }

    注:

      默认枚举实例的创建是线程安全的,所以不需要担心线程安全的问题。但是在枚举中的其他任何方法的线程安全由程序员自己负责。还有防止上面的通过反射机制调用私用构造器。

    参考文章:

    单例模式

    深入浅出单实例Singleton设计模式

  • 相关阅读:
    [转]使用@Test 也可以从spring容器中获取依赖注入
    idea/ecipse中使用maven集成springmvc相关jar包时候,出错:java.lang.ClassNotFoundException: org.springframework.web.servlet.DispatcherServlet
    mongodb 权限设置--用户名、密码、端口
    java中import static和import的区别【转】
    python 数字的四舍五入的问题
    数据库——索引(面试、笔试必会)
    Python 中的那些坑总结——持续更新
    python2和python3的区别——持续更新
    常用的排序算法的时间复杂度和空间复杂度
    Libpacp 深度剖析
  • 原文地址:https://www.cnblogs.com/lemon-now/p/5149028.html
Copyright © 2011-2022 走看看