几种单例模式总结

我的博客地址https://home.cnblogs.com/u/wdfwolf3/。转载注明出处,谢谢。面试

  面试被要求写一个单例模式,想不起来双重锁的写法,就写了一个普通的饿汉模式。简单问题没答好,面试减去不少分数。回来翻看笔记,从新过了一遍,在博客中整理记录一下。安全

1.懒汉式,线程不安全app

public class Lazy {
    private static Lazy instance;
    private Lazy(){}

    public static Lazy getInstance() {
        if (instance == null)
            instance = new Lazy();
        return instance;
    }
}

2.懒汉式,线程不安全ide

public class Lazy {
    private static Lazy instance;
    private Lazy(){}

    public static synchronized Lazy getInstance() {
        if (instance == null)
            instance = new Lazy();
        return instance;
    }
}

3.饿汉式,线程安全 函数

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

4.双重校验锁,线程安全优化

  因为线程安全的懒汉式在任什么时候候只能有一个线程调用 getInstance() 方法,可是同步操做只须要在第一次建立单例实例对象时才被须要,因此它并不高效。这就出现了双重检验锁来解决这个问题。为何在同步块内要检验两次,由于可能会有多个线程一块儿进入同步块外的 if,若是在同步块内不进行二次检验的话,阻塞的线程得到锁以后又会new一个新的对象,就会生成多个实例了。spa

 

public class DoubleLock {
    private volatile static DoubleLock instance;

    private DoubleLock() {
    }

    public static DoubleLock getSingleton() {
        if (instance == null)
            synchronized (DoubleLock.class) {
                if (instance == null)
                    instance = new DoubleLock();
            }
        return instance;
    }
}

 

  这里对instance使用了volatile关键字,主要是用它的禁止指令重排序功能。new Singleton()并不是是一个原子操做,在 JVM 中作了下面 3 件事情,线程

  a.给 instance 分配内存code

  b.调用 Singleton 的构造函数来初始化成员变量orm

  c.将instance对象指向分配的内存空间(执行完这步 instance 就为非 null 了)

  JVM可能将语句c优化到语句b以前,当一个线程执行完c没有执行b,而后释放锁,另一个线程得到锁,此时判断instance!=null,直接返回,那就会出错。

5.静态内部类,线程安全

public class Inner {
    private static class SingletonHolder {
        private static final Inner INSTANCE = new Inner();
    }

    private Inner() {
    }

    public static final Inner getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

6.枚举,线程安全

public enum SingletonEnum {
    INSTANCE;
}

 

 

1、懒汉式,线程不安全

相关文章
相关标签/搜索