两种单例模式:饿汉式和懒汉式以及优化

单例模式就是一种设计模式,即强制使对象只能有一个实例就称为单例模式。

今天分析两种单例模式,一种是饿汉式,一种是懒汉式:

饿汉式代码实现:

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

 不难看出饿汉式的单例模式属于线程安全的模式(一般的,通过直接给int,short,byte,char,boolean赋值操作属于线程安全,给double,long这些引用类型赋值属于线程不安全;而进行判断操作,运算操作一般都属于线程不安全)。

懒汉式代码实现:

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

相比较来说:懒汉式更符合平时的需求,即使用的时候才创建实例,但是由于线程不安全导致了诸多的问题,例如:多线程下在if判断的时,线程一获取到instance之后线程二也获取到instance,但此时instance的值均为null,因此两个线程将创建两个实例,不满足单例模式的要求。

两种单例模式:饿汉式和懒汉式以及优化_第1张图片

对此我们可以对懒汉模式的代码进行优化:

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

对于程序来说,加锁解锁可是一个重量级的工程,一个程序如果频繁的加锁解锁那么这个代码的执行效率就对不会高。

通过分析代码我们可以观察到创建实例的过程只需要发生一次就可以了,那么是否可以用一个双重判断减少后续的加锁解锁的操作呢,与此同时应该注意一下JVM所带有的一种特殊属性:内存可见性(即可能只进行一次读取操作之后多次执行其他操作再将其存入内存当中)我们可以直接通过volatile来保证内存可见性和禁止指令重排序,通过这两点我们可以继续对代码进行优化:

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

对于懒汉模式的优化也是面试时常考的点,总结起来我们只需要注意以下三点:

1.对于synchronized的加锁位置要同时确保将if和new操作都包裹起来,并且范围不能太大。

2.双重if条件能够确保该代码的执行效率。

3.volatile确保变量内存可见性,使得外层if读取的数据都是最新的。

你可能感兴趣的:(java)