zoukankan      html  css  js  c++  java
  • 基础设计模式-01 单例设计模式

      单例模型:要求一个类只有一个实例,并且对外提供全局的访问方法。

    1.懒汉式和饿汉式的单例模型

    1.1 懒汉式

        懒汉式单例模式,是在类被加载的时候,通过静态初始化的方式实例化。

    public class Layzerbones {
        private static Layzerbones layzer = new Layzerbones();
        private Layzerbones(){}
        public static Layzerbones getInstance(){
            return layzer;
        }
    }

    1.2 饿汉式

      饿汉式单例模式,是在第一次被调用的时候进行实例化;

    public class Badmash {
        private static Badmash badmash;
        private Badmash(){}
        public static synchronized Badmash getInstance(){//方法一
            if(badmash == null){
                badmash = new Badmash();
            }
            return badmash ;
        }
        public static Badmash getInstance2(){//方法二
            if(badmash == null){
                synchronized (Badmash.class){
                    if(badmash == null){
                        badmash = new Badmash();
                    }
                }
            }
            return badmash ;
        }
    }

    上面两种单例模型的共同点

    1.当前类做为静态成员变量;2.构造器私有化;3.提供静态可访问实例化方法;

    不同点在于:

    1.懒汉式:线程安全;

    2.饿汉式,线程不安全,所以要增加锁;

    3.饿汉式的锁,有两种方式,一种是在方法上加锁,锁是类的字节码文件;另一种是synchorinize代码块,可以自定义锁

    4.synchorinize代码块的双重校验的目的是提高执行的效率;

    2.饿汉式的双重检查锁定的问题及优化

           问题在于现有的逻辑代码,在编译器编译期间可能会发生重排序的情况;

      

    这个是《JAVA并发编程艺术》中的附图,很清晰的说明了问题;如下说所示;

     

    正常对象的初始化顺序是:1.先给对象分配内存空间;2.初始化对象;3.将初始化的实例指向分配的内存地址

    但是问题在于,由于JMM内部重排序,初始化对象,和实例地址指向内存地址的可以重排序;

    那么出现的问题就会有:在对象还没有初始化,就已经指向了内存地址,对象为null;当另一个线程再次访问的时候,又会进行判断,为null,重新进行初始化对象。

     当然,对于存在的这种问题,比较好解决的,给静态成员增加volatile修饰符,这是一个轻量锁,使修饰的变量具有原子性

        private volatile static Badmash badmash;

    当然还有其他方法也可以,避免这种问题。

    3.静态内部类单例设计模型

          为了避免上面的对象初始化重排的问题,可以利用类在初始化过程中加锁的原理,通过内部类实现单例;

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

    4.枚举单例模式

         1.在枚举中设置实例枚举INSTINCT

         2.然后再私有的构造器中对需要初始化的对象进行初始化

         3.提供对外的非静态的获取实例的方法

    public enum SingleEnum {
    INSTINCT;
    private User user ;
    SingleEnum(){
    user = new User();
    }
    public User getInstance(){
    return user;
    }
    }

    以上就是最常见的单例模型!

    至此,完毕!

  • 相关阅读:
    Taxes
    Tennis Championship
    Urbanization
    字符串的匹配
    Alyona and a tree
    Alyona and mex
    Alyona and flowers
    Alyona and copybooks
    Subordinates
    线程的暂停、恢复和终止
  • 原文地址:https://www.cnblogs.com/perferect/p/12760832.html
Copyright © 2011-2022 走看看