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

    1、单例模式定义

      单例模式可定义为:一个类只有一个实例,并且该类能够自行创建此实例的模式。在Java中,单例模式可以保证一个类在JVM中只有一个实例对象存在。

      一般情况下,我们定义一个普通的类之后,当需要该类的实例对象时只需要通过new操作符就可以获得此类的一个实例对象,这是因为Java类都包含一个或一个以上的构造方法,构造方法用于构造该类的实例对象,Java语言通过new关键字来调用构造方法,从而返回该类的实例对象。还需要明确的是,当没有在类中自定义构造方法时候,系统会为类提供一个默认的无参构造方法。

      综合以上可知,单例模式中的类,需要对构造方法进行特殊处理,不能让构造方法在外部被调用而产生类的实例对象(否则可能会破坏实例对象的唯一性),可以用private修饰符修饰构造方法来达到禁止外部访问构造方法的目的,也即在类中显示定义私有的构造方法。

    2、单例模式特点

      (1)由于单例模式只生成一个实例对象,所以减小了系统的性能开销。尤其是对于创建实例对象消耗资源较多的类,此好处更加明显。

      (2)由于不是采用new操作符的方式创建类的实例对象,所以不用频繁的在系统内存中开辟内存创建实例以及进行GC操纵,也即降低了系统内存的使用频率,减小了GC压力。

      (3)单例类对外提供一个访问该单例的全局访问点,优化了共享资源的访问方式。

    3、单例模式的实现和分析

      (1)饿汉式实现单例模式

        (a)饿汉式

          饿汉式实现的特点是在类加载的时候就开始创建一个实例,具体代码如下:

    package com.singleton;
    public class SingleTon01 {
        //类初始化的时候立即初始化instance对象
        private static SingleTon01 instance = new SingleTon01();
        private SingleTon01() {}
        //getInstance方法没有同步,所以效率较高
        public static SingleTon01 getInstace() {
            return instance;
        }
    }

        (b)分析:

        (I)instance是静态私有变量,保证了只能在类内部访问,而且在类加载的时候创建实例对象

        (II)类的构造方法是私有的,这一点很重要,一般类的构造方法是共有的,从而保证在程序中可以使用new操作符来创建类的对象。但是在单例模式中不允许通过new来创建对象(否则可能会出现多个实例,违反了单例的定义),所以要把类的构造方式设置为private。

        (III)getInstance方法需要设置为public,也即对外提供一个共有的方法来创建或获取该静态私有实例

        (c)测试

    package com.singleton;
    public class Client {
        public static void main(String[] args) {//饿汉式单例模式实现
            //此处创建两个SingleTon01类的对象,打印输出查看是否是同一个对象,如果输出的是同一个对象,则满足单例要求
            //因为SingleTon01中的getInstance给定义为static方法,所以使用的时候通过类名来调用
            SingleTon01 s1 = SingleTon01.getInstace();
            SingleTon01 s2 = SingleTon01.getInstace();
            System.out.println(s1);
            System.out.println(s2);       
        }
    }

        (d)运行结果:

    com.singleton.SingleTon01@15db9742
    com.singleton.SingleTon01@15db9742

      打印结果一样,证明了两个对象是同一个对象。

     

      (2)懒汉式实现单例模式

        (a)懒汉式

          懒汉式实现的特点是在类加载的时候没有创建实例,而是在实际使用(也即第一次调用getInstance方法)的时候再去创建实例,也即所谓的延迟加载。

    package com.singleton;
    //此案例为懒汉模式,也即在创建类的时候没有立即加载对象,而是进行延迟加载
    public class SingleTon02 {
        //也是静态私有对象,但是不进行初始化
        private static SingleTon02 instance;
        private SingleTon02() {}
        //对方法进行同步,保证了唯一性,并发性降低了
        public static synchronized SingleTon02 getInstance() {
            if(instance == null) {
                instance = new SingleTon02();
            }
            return instance;
        }
    }

        (b)分析

          getInstance方法被synchronized修饰符所修饰,在多线程环境下也能保证线程安全。但是会影响系统的性能。

        (c)测试

    package com.singleton;
    public class Client {
        public static void main(String[] args) {//懒汉式单例模式实现
            SingleTon02 s1 = SingleTon02.getInstance();
            SingleTon02 s2 = SingleTon02.getInstance();
            System.out.println(s1);
            System.out.println(s2);        
        }
    }

        (d)运行结果

    com.singleton.SingleTon02@15db9742
    com.singleton.SingleTon02@15db9742

     

      (3)静态内部类实现单例模式

        (a)静态内部类

          单例模式使用静态内部类来维护单例的实现时,JVM内部的机制能够保证当一个类被加载时类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕。同时该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低性能问题。

    package com.singleton;
    public class SingleTon03 {
        //私有的静态内部类
        private static class InnerClass{
            //静态内部类中有一个私有的静态变量instance,变量的类型是外部类的类型
            private static final SingleTon03 instance = new SingleTon03();
        }
        //私有构造方法,防止在外部被实例化
        private SingleTon03() {} 
        //公有的获得实例的方法
        public static SingleTon03  getInstance(){
            return InnerClass.instance;//可以访问此静态类内部的属性instance
        }
    }

        (b)分析

          在类中定义一个私有的静态内部类,内部类中定义一个私有的外部类的变量instance,用作最终返回的实例。

        (c)测试

    package com.singleton;
    //单例模式,是保证在整个程序中,某个类的对象有且只能一个
    public class Client {
        public static void main(String[] args) {
            SingleTon03 s1 = SingleTon03.getInstance();
            SingleTon03 s2 = SingleTon03.getInstance();
            System.out.println(s1);
            System.out.println(s2);        
        }
    }

        (d)运行结果

    com.singleton.SingleTon03@15db9742
    com.singleton.SingleTon03@15db9742
  • 相关阅读:
    maven学习(七)——使用maven构建java项目
    Java 实现word 中写入文字图片的解决方案
    postman中如何传数组
    char类型在传参时接收不到数据的原因
    Oracle一条数据多表连插
    Spring Cloud Config的配置中心使用非对称性加密
    Failed to read artifact descriptor for org.springframework.cloud:spring-cloud-starter-config:jar:unk
    如何上传文件到git
    Windows的DOS命令
    ideal的maven项目不小心remove module,如何找回
  • 原文地址:https://www.cnblogs.com/xwwbb/p/11094141.html
Copyright © 2011-2022 走看看