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

    关于单例模式,话不多说,即程序运行时无论New了多少次,即内存中只有一个实例对象。即对象的HasHCode一致。

    单例模式的两大类

    1、饿汉模式(即加载时就创建对象)

      -1、直接实例化饿汉模式

      -2、静态代码块饿汉模式(即需要加载初始化配置的时候适用)

      -3、枚举方式

    2、懒汉式(延迟加载)

      -1、单线程安全下的懒汉

      -2、多线程安全下的懒汉

      -3、静态内部类的懒汉(安全)

      


      1、直接实例化饿汉模式

      

    package com.single;
    
    public class Singleton {
       
        private static final Singleton SI=new Singleton();
    
        private Singleton(){
    
        }
    
        public static Singleton getsingleton(){
            return SI;
        }
    }

      单例模式必须保证自行创建,并且内部提供一个静态变量来保存这个唯一的对象,构造器私有化,即其他类内部中无法直接New当前的单例类,还需要提供一个对外获取实例的方法

      当前模式在加载类的字节码的时候当前类的实例就立即会被创建

      2、静态代码块饿汉模式(即需要加载初始化配置的时候适用)

      

     1 public class Singleton2 {
     2 
     3     private static final Singleton2 SI;
     4 
     5     private String name;
     6     static {
     7         Properties properties=new Properties();
     8         try {
     9      
    10             properties.load(Singleton2.class.getClassLoader().getResourceAsStream("db.properties"));
    11             String name = properties.getProperty("name");
    12             SI=new Singleton2(name);
    13         } catch (IOException e) {
    14             throw new RuntimeException(e);
    15         }
    16 
    17     }
    18 
    19     private Singleton2(String name){
    20         this.name=name;
    21     }
    22 
    23     public static Singleton2 getsingleton(){
    24         return SI;
    25     }

     当我们需要在类创建的时候初始化参数,并且加载某些配置文件的时候可以使用 静态代码块的方式,在创建实例的时候通过构造器来完成相关参数的初始化。

     3.枚举方式的单例,自JDK1.5之后,首先枚举类和普通类的区别是什么?

    使用enum定义的枚举类默认继承了java.lang.Enum类

    枚举类的构造器只能使用private

    枚举类的每个实例必须在枚举类中显示的列出(,分隔   ;结尾) 列出的实例系统会自动添加public static final修饰

    所有的枚举类都定义了一个values方法,该方法可以很方便的遍历所有的枚举值

    可以在switch表达式使用枚举类对象作为表达式,case子句可以直接使用枚举的名字,无需添加枚举类作为限定

    枚举类对象的属性不能更改,所以要用private final修饰

    枚举类对象要在构造器中被赋值
    ---------------------
    作者:weirdowang
    来源:CSDN
    原文:https://blog.csdn.net/weirdowang/article/details/79970673

    package com.single;
    /*
    枚举方式的单例
     */
    public enum SingEnum {
        SING;
        SingEnum(){
    
        }
        public void info(){
            System.out.println("显示");
        }
    }

      是不是很简洁呢? 确实如此,单例模式下 枚举方式的单例是最简洁的

      二、懒汉模式


      1、单线程安全下的懒汉

      

    package com.single2;
    /*
        懒汉模式
     */
    public class Singleton {
        private static Singleton singleton;
    
        private Singleton(){
            System.out.println("创建");
        }
    
        public static Singleton getSingleton(){
            if (singleton==null){
                singleton=new Singleton();
            }
            return singleton;
        }
    
    
    }

      我们可以看出无论怎么样,当前的懒汉都是在调用的时候才被加载创建的,但是它只是在单线程的情况下是安全的为什么呢? 现在有一个需求即多个线程对这个 单例进行访问构建对象,在构建对象的时候使当前线程短暂的休眠一下

    package com.single2;
    /*
        懒汉模式测试线程不安全
     */
    public class Singleton2 {
        private static Singleton2 singleton;
    
        private Singleton2(){
            System.out.println("创建");
        }
    
        public static Singleton2 getSingleton() throws InterruptedException {
            if (singleton==null){
                Thread.sleep(100);
                singleton=new Singleton2();
            }
            return singleton;
        }
    
    
    }

    测试代码如下:

      

      /*
        懒汉模式下的多线程不安全
         */
        public static void main(String[] args) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                    Singleton2 singleton1 = Singleton2.getSingleton();
                    System.out.println(singleton1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            Thread thread2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Singleton2 singleton2 = Singleton2.getSingleton();
                        System.out.println(singleton2);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            thread.start();
            thread2.start();
        }

      经过测试,多线程情况下这种是不安全的 为什么呢?  第一个线程进入 进去之后, 线程休眠100ms 在此期间,第二个线程也开始进去到了创建的方法,由于当前第一个线程正在休眠,所以当前单例为null ,然后第一个线程休眠结束,创建第一个对象,此后第二个线程还在if中,也相继创建对象,此时便构造成了线程不安全的懒汉单例

      2、线程安全的懒汉单例(双端检索)

    package com.single2;
    
    /*
    懒汉模式 双端检索,避免了多次线程等待
     */
    public class Singleton4 {
        private static Singleton4 singleton4;
    
        private Singleton4() {
    
        }
    
        public static Singleton4 getSingleton4() {
            if (singleton4 == null) {
                synchronized (Singleton4.class) {
                    if (singleton4 == null) {
                        try {
                            Thread.sleep(100);
    
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        singleton4 = new Singleton4();
                    }
                }
            }
            return singleton4;
        }
    
    }
    使用synchronized 保证当前只能有一个线程进入 ,并且在外再次进行判断 若当前的单例已经被创建过了,避免了再次加锁,直接返回 
    3、静态内部类的懒汉单例:(线程安全的)
    package com.single2;
    
    public class Singleton5 {
        private Singleton5(){
    
        }
    
        private static class demo{
            private static final Singleton5 SINGLETON_5=new Singleton5();
        }
    
        public static Singleton5 singleton5(){
            return demo.SINGLETON_5;
        }
    
    
    }

    也是懒汉模式最简单的单例实现,静态内部类不会随着外部类的初始化而初始化,并且内部类具有自己的类加载器,是安全的

    如上便是单例模式的六种创建方式,欢迎大牛指正,源码放到群里了  另外也欢迎各位朋友们一起学习交流, qq群:956809929

     
  • 相关阅读:
    有限元方法的核心思想
    由拉格朗日函数推导守恒定律
    codeforces 1181D
    gym 102222 J
    COJ#10C
    已然逝去の夏日泳装
    NC50 E
    codeforces 1147 C
    agc 037 C
    19牛客多校第十场G
  • 原文地址:https://www.cnblogs.com/Mzcc/p/10747692.html
Copyright © 2011-2022 走看看