单例模式的五种写法

背景知识

谈到单例模式时总是有懒汉式和饿汉式的说法,我们先来看看懒汉式和饿汉式的特点

懒汉式:
1.在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的
2.懒汉式是延时加载,需要的时候在创建对象
3.懒汉式需要关注线程同步的问题,优点是只在需要的时候创建加载对象

饿汉式:
1.线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变
2.饿汉式在加载类时创建实例
3.饿汉式无需关注多线程问题,写法简单明了。但如果是一个工厂模式、缓存了很多实例、就需要考虑效率问题,因为这个类一加载会把所有实例一起创建。

实现方式

第一种(懒汉式,线程不安全)

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

问题:能实现懒加载,但多线程时会出现问题

第二种(懒汉式,线程安全)

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

问题:能实现懒加载,线程也是安全的,但是对所有的操作进行加锁操作,效率低

第三种(饿汉式)

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

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

问题:实现差别表面看着挺大,其实本质都是一样,加载的时候就创建对象,涉及效率问题

第四种(静态内部类)

/**  
     * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例  
     * 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载  
 */
public class Singleton {
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();// 静态初始化器,由JVM来保证线程安全
    }
    private Singleton (){}
    public static final Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

问题:能实现懒加载,线程也是安全的,类被加载后如果没有调用getInstance()方法那么instance不会被加载,能达到一个懒加载的目的

第五种(双重校验)

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

问题:能实现懒加载,线程也是安全的,大家比较常用的一种方式

总结

第一和第二种不建议使用。个人推荐第三种和第四种方式,简单易懂,而且在JVM层实现了线程安全(如果不是多个类加载器环境),一般的情况下第三种方式就能满足需求,只有在要明确实现懒加载效果时才会使用第四种方式,如果有其他特殊需求建议第五种。

参考:

http://cantellow.iteye.com/blog/838473
http://blog.csdn.net/abc19900828/article/details/39479377

你可能感兴趣的:(java)