常见设计模式-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.饿汉式的双重检查锁定的问题及优化

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

扫描二维码关注公众号,回复: 11075912 查看本文章

  

这个是《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;
}
}

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

至此,完毕!

猜你喜欢

转载自www.cnblogs.com/perferect/p/12760832.html