暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Spring中Bean的单例及七种创建单例的方法

7438

1. 单例(singleton):只有一个共享的实例存在,所有对这个bean的请求都会返回这个唯一的实例。eg:每个国家(spring)有一个总统(bean),国家的所有人(其他调用者)共享此总统。

 

2. 多例(pototype):对这个bean每次请求都会创建一个新的bean实例,类似于new

 

3. SpringBoot采用的是单例模式、@Component注解默认实例化的对象是单例,如果想声明成多例对象,可以使用@Scope(pototype)@Respository默认单例、@Service默认单例、@Controller默认单例

 

4. 单例bean与单例模式:

(1)单例模式:在一个JVM进程中仅有一个实例(一个运行的Java程序必定有一个自己独立的JVM),无论在程序的何处获取实例,始终都返回一个对象 egJava内置的Runtime,无论在程序的何处获取实例,Runtime.getRuntime == Runtime.getRuntime 结果为true(例如建立目录、数据库的连接都需要单线程操作),单例模式能避免实例的重复创建、避免多个实例引起程序逻辑错误、节约内存。

(2)Spring单例beanSpring的单例bean是与其容器(ApplicationContext)相关的,所以在一个JVM进程中,若有多个Spring容器,即使是单例bean,也会创建多个实例(如果在实际应用中,对象的状态会改变,就使用多例)

 

5. Springbean默认设置为单例的原因:

(1)提高性能,减少了新生成实例的消耗

(2)减少了JVM的垃圾回收

(3)可以快速获取到bean(单例的获取除了第一次生成之外都是从缓存中获取的)

 

 

6. 七种创建单例的方式:

(1)饿汉式:

    public  class Singleton1{
    private static Singleton1 singleton1 = new Singleton1();
    public static Singleton1 getSingleton1(){
    return singleton1;
    }
    }
    复制

    singleton1作为类变量直接得到初始化,优点是在多线程环境下能够保证同步,不可能被实例化两次,但是如果singleton1在很长一段时间后才使用,意味着singleton1实例开辟的堆内存会驻留很长时间,不能延迟加载,占用内存

    (2)懒汉式:

      public  class Singleton2{
      private static Singleton2 singleton1 = null;
      public static Singleton2 getSingleton1(){
      if(singleton1 ==null){
      singleton1 = new Singleton2();
      }
      return singleton1;
      }
      }
      复制

      懒汉式,是在使用的时候才去创建,这样可以避免类在初始化时提前创建,但是如果在多线程的情况下,若一开始因为线程上下文切换的原因,导致两个线程都通过了if判断,这样就new出两个实例,无法保证唯一性。延迟加载,但在多线程环境下不安全。

      (3)懒汉式+同步:

        public class Singleton3 {
        private static Singleton3 singleton1 = null;
        public synchronized Singleton3 getSingleton1() {
        if (singleton1 == null) {
        singleton1 = new Singleton3();
        }
        return singleton1;
        }
        }
        复制

        这种方法通过添加同步控制,满足了懒加载和singleton1实例的唯一性,但是添加同步控制后,getSingleton1()方法是串行化的,获取时需要排队等候,效率较低。

        (4)懒汉式+双重检验:

          ublic class Singleton4 {
          private static Singleton4 singleton1 = null;
          public static Singleton4 getSingleton1() {
          if (singleton1 == null) {
          synchronized (Singleton4.class) {
          if (singleton1 == null) {
          singleton1 = new Singleton4();
          }
          }
          }
          return singleton1;
          }
          }
          复制

          若有两个线程通过了第一个check,进入第二个check是串行化的,只能有一个线程进入,保证了唯一性,也不会有同步控制,可能会引起空指针异常,但是可能会出现JVM排序的问题

          (假设这个单例创建有一些其他的资源,例如SocketConnection,这些资源在构造函数中也会被实例化,那样在创建单例的时候,就是要实例化自身还有Socket这些资源,那根据JVM的重排序和Happens-before原则,有可能会出现先实例化自身,再去实例化Socket这些资源,若在此时只实例化了自己的情况下,别的线程调用了这个单例中Socket这些资源的方法,而此时它们可能还没有被实例化,这样就会抛出空指针的异常)

          (5)懒汉式+双重检验+volatile

          Volatile关键字禁止指令重排序:

            public class Singleton5 {
            private static volatile Singleton5 singleton1 = null;
            public static Singleton5 getSingleton1() {
            if (singleton1 == null) {
            synchronized (Singleton5.class) {
            if (singleton1 == null) {
            singleton1 = new Singleton5();
            }
            }
            }
            return singleton1;
            }
            }
            复制

            (6)Holder方式(静态内部类):

              public class Singleton6 {
              private Singleton6(){
              }
              private static class Singleton{
              private static Singleton6 singleton1 = new Singleton6();
              }
              public static Singleton6 getInstance(){
              return Singleton.singleton1;
              }
              }
              复制

              Singleton6中并没有singleton1的静态成员,而是放在静态内部类Singleton中,因此Singleton6的初始化并不会实例化singleton1,只有当Singleton被主动引用的时候才会实例化。

              (7)枚举法:

                public class Singleton7 {
                private Singleton7(){
                }
                private enum Singleton{
                Singleton;
                private final Singleton7 singleton7;
                Singleton(){
                singleton7 = new Singleton7();
                }
                public Singleton7 getSingleton7() {
                return singleton7;
                }
                }
                }
                复制

                 


                文章转载自琢磨先生DataBase,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                评论