设计模式--单例模式

确保一个类只有一个实例,并提供全局访问点。私有化构造器,静态方法和静态变量

管理共享资源:线程池、缓存、偏好设置

全局变量和单例模式 :急切实例化VS延迟实例化

1.懒汉式

public class Singleton {
    private static Singleton instance = null;
    private Singleton(){
    }
    public static Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

线程安全版本:

1.使用同步方法(synchronized关键字),性能差

public class Singleton {
    private static Singleton instance = null;
    private Singleton(){
    }
    public static synchronized Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

2.使用饿汉式(急切实例化,JVM加载时,就会创建唯一的实例)

public class Singleton {
    //私有化成员变量
    private static Singleton instance = new Singleton();
    //私有化构造器
    private Singleton(){
    }
    //只提供public的getter方法,但是没有setter方法
    public static Singleton getInstance(){
        return instance;
    }
}

3.用“双重检查加锁”,来减少使用同步

public class Singleton{
    private volatile static Singleton instance = null;
    private Singleton(){
    }
    public static Singleton getInstance(){
        if(instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
在懒汉式的线程安全版本中,也可能存在问题
* 在Java指令中创建对象和赋值操作是分开进行的,
* 也就是说instance = new Singleton();语句是分两步执行的。
* 但是JVM并不保证这两个操作的先后顺序,也就是说有可能JVM会为新的Singleton实例分配空间,
* 然后直接赋值给instance成员,然后再去初始化这个Singleton实例。这样就可能出错了,
* 我们以A、B两个线程为例:
a>A、B线程同时进入了第一个if判断
b>A首先进入synchronized块,由于instance为null,所以它执行instance = new Singleton();
c>由于JVM内部的优化机制,JVM先画出了一些分配给Singleton实例的空白内存,
并赋值给instance成员(注意此时JVM没有开始初始化这个实例),然后A离开了synchronized块。
d>B进入synchronized块,由于instance此时不是null,
因此它马上离开了synchronized块并将结果返回给调用该方法的程序。
e>此时B线程打算使用Singleton实例,却发现它没有被初始化,于是错误发生了。
* 采用静态内部类的方法来创建
* 单例模式使用内部类来维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候,
* 这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,
* JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,
* 这样我们就不用担心上面的问题。同时该方法也只会在第一次调用的时候使用互斥机制,
* 这样就解决了低性能问题
public class Singletone3 {
    /*私有化构造器*/
    private  Singletone3(){
    }
    /*使用内部类来维护单例模式*/
    private static class SingletoneFactory{
        private static Singletone3 instance = new Singletone3();

    }
    /*获取实例*/
    public static Singletone3 getInstance(){
        return SingletoneFactory.instance;
    }
}

  




 

posted @ 2018-06-14 09:55  SkyeAngel  阅读(114)  评论(0编辑  收藏  举报