面试题七种方式实现Singleton模式

实现单例的几种常见方式及特点分析

  • 1.懒汉式,线程安全,直接创建对象,然后判断是否为空
public class Test {

    /**
     * 单例模式,懒汉式,线程安全 final限定实例不可再改变
     * 特点:实现方式简单
     */
    public static class Singleton1 {
        private final static Singleton1 INSTANCE = new Singleton1();

        private Singleton1() {

        }

        public static Singleton1 getInstance() {
            return INSTANCE;
        }
    }
  • 2.懒汉式,线程不安全,只适合单线程,很费时间
/**
  * 特点:懒汉式,线程不安全
  * 缺陷:如果两个线程同时运行到判断instance是否为null的if语句,并且instance没被创建时,那么两个线程都会创建一个实例,就不再满足单例模式的要求了。
  */
    public static class Singleton2 {
        private static Singleton2 instance = null;

        private Singleton2() {

        }

        public static Singleton2 getInstance() {
            if (instance == null) {
                instance = new Singleton2();
            }
            return instance;
        }
    }
  • 3.饿汉式,线程安全,多线程环境下效率不高
/**
  * 单例模式,饿汉式,线程安全,多线程环境下效率不高,加同步锁
  * 缺陷:获取实例的方法中添加了同步锁,会降低获取实例的效率,
  * 假设当instance已经被创建过了,即不为空的情况下,这种方式还会先加同步锁,再判断instance是否为空,这是没有必要的,也就是读取instance是不需要处理并发读操作可能带来的问题。
  */
    public static class Singleton3 {
        private static Singleton3 instance = null;

        private Singleton3() {

        }

        public static synchronized Singleton3 getInstance() {
            if (instance == null) {
                instance = new Singleton3();
            }
            return instance;
        }
    }
  • 4.懒汉式的变形,线程安全
/**
  * 单例模式,懒汉式,变形,线程安全,static代码中创建实例
  * 特点:static会在类被加载时编译,所以只要类被载入内存编译,那么instance肯定就被创建了,这样减少了判断和加锁的操作。
  */
    public static class Singleton4 {
        private static Singleton4 instance = null;

        static {
            instance = new Singleton4();
        }

        private Singleton4() {

        }

        public static Singleton4 getInstance() {
            return instance;
        }
    }

懒汉式和饿汉式单例的区别:

  • 懒汉式是以空间换时间,饿汉式是时间换空间
  • 懒汉式在多线程环境下可能创建多个对象

  • 5.使用静态内部类,线程安全,推荐使用

    /**
     * 单例模式,使用静态内部类,线程安全(推荐)
     */
    public static class Singleton5 {
        private final static class SingletonHolder {
            private static final Singleton5 INSTANCE = new Singleton5();
        }

        private static Singleton5 getInstance() {
            return SingletonHolder.INSTANCE;
        }
    }
  • 6.静态内部类,使用枚举方式,线程安全,推荐使用
    /**
     * 静态内部类,使用枚举方式,线程安全(推荐)
     */
    public enum Singleton6 {
        INSTANCE;
        public void whateverMethod() {

        }
    }
  • 7.静态内部类,使用双重校验锁(volatile和synchronized),线程安全,推荐使用
    /**
     * 静态内部类,使用双重校验锁,线程安全(推荐)
     */
    public static class Singleton7 {
        private volatile static Singleton7 instance = null;

        private Singleton7() {

        }

        public static Singleton7 getInstance() {
            if (instance == null) {
                synchronized (Singleton7.class) {
                    if (instance == null) {
                        instance = new Singleton7();
                    }
                }
            }
            return instance;
        }
    }
}
  • 类似Spring里面的方法,将类名注册,下次从里面直接获取
import java.util.HashMap;
import java.util.Map;

//类似Spring里面的方法,将类名注册,下次从里面直接获取。  
public class Singleton3 {
    private static Map<String, Singleton3> map = new HashMap<String, Singleton3>();

    static {
        Singleton3 single = new Singleton3();
        //编译时反射
        map.put(single.getClass().getName(), single);
    }

    // 保护的默认构造子
    protected Singleton3() {
    }

    // 静态工厂方法,返还此类惟一的实例
    public static Singleton3 getInstance(String name) {
        if (name == null) {
            name = Singleton3.class.getName();
            System.out.println("name == null" + "--->name=" + name);
        }
        if (map.get(name) == null) {
            try {
                map.put(name, (Singleton3) Class.forName(name).newInstance());
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return map.get(name);
    }

    // 一个示意性的商业方法
    public String about() {
        return "Hello, I am RegSingleton.";
    }

    public static void main(String[] args) {
        Singleton3 single3 = Singleton3.getInstance(null);
        System.out.println(single3.about());
    }
}

猜你喜欢

转载自blog.csdn.net/yyg_2015/article/details/56321529