java单例模式与线程安全实例分析
设计模式在软件架构设计中被经常使用,掌握常用的设计模式对于设计软件系统非常重要。单例模式作为设计模式中最简单和常用的一种模式,java中单例模式具有多种实现方式,以下会对各种实现进行解析。
1、单例模式概念:
顾名思义,单例模式指的是在软件系统运行过程中,某个类只存在一个实例。因此一个类实现单例模式时需要具备以下3个条件:
1)类的内部定义一个该类的静态私有成员变量;
2)构造方法为私有;
3)提供静态工厂方法,供外部获取类的实例;
2、单例模式实现方式:
1)懒汉式单例
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public synchronized static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
懒汉式单例即在使用使用时才创建类的实例,工厂方法增加类synchronized关键字以保证线程安全。在多线程访问的环境下,同步方法导致系统性能下降。优点在于,类加载时不用自行实例化对象,避免加载缓慢。
2)饿汉式单例
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
饿汉式单例,在类加载式自行实例化对象。优点在于多线程环境下不会出现线程安全问题,因为类只加载一次。缺点在于,系统加载时消耗额外资源,如果该实例没有使用的情况会造成资源浪费。
3)双重检测单例
public class Singleton {
private static volatile Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
双重检测锁定(Double-Check Locking)方案属于懒汉式,使用延时加载技术,避免类加载时任务过重和造成资源浪费,同时将synchronized关键字加在代码块中,减少线程同步锁定以提升系统性能。instance实例使用了volatile关键字修饰,主要是避免在多线程环境下由于编译器进行的重排序操作而导致的线程安全问题。JVM在创建一个对象时会进行以下步骤:
1)分配对象内存空间;
2)初始化对象;
3)设置instance指向分配的内存地址;
编译器为了优化性能,可能会将2、3操作调换顺序,假设A线程在执行new Singleton()方法时,由于2、3操作重排序,而初始化对象操作尚未完成时释放了锁。线程B获取锁之后会发现instance已经不为空,当线程B获取到instance对象后如果直接使用就会出错,原因就是对象没有进行初始化操作。而volatile关键字能避免重排序,因此能保证线程安全。总体上来说,双重检测由于加了锁,多线程并发下还是会有效率问题。
4)枚举单例
public enum Singleton {
INSTANCE
}
枚举单例模式,不会存在线程安全问题,不过在Android平台下,枚举类性能相对较低。
5)静态内部类单例
public classSingleton {
private Singleton() {
}
public static Singleton getInstance() {
return SingletonFactory.instance;
}
static class SingletonFactory {
private final static Singleton instance = new Singleton();
}
}
静态内部类单例模式是一种比较优秀的实现方式,也是《Effective Java》书中推荐的方式。一方面,使用延时加载,使用时才进行对象初始化,也不会造成造成资源浪费;另一方面,由于JVM在类的加载时已经做了同步处理,不会出现线程安全问题。
结束语
文中介绍单例模式的一些基础知识点,以及多种实现方式的优缺点分析。在日常开发中,推荐使用静态内部类实现单例模式。相对其他设计模式而言,单例模式是非常简单的。