1.为什么要用单例模式?
(1)对于频繁使用的对象,可以省略对象创建时所消耗的时间。尤其是对重量级系统而言是一个非常可观的系统开销。
(2)由于new对象的次数变小,系统的内粗消耗也会降低,可以减轻gc的压力,缩短gc停顿时间。
2.设计单例模式的几种方法
(1)简单的单例模式
public class Singleton {
private Singleton() {
System.out.println("Singleton is created");
}
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
这种设计单例模式的方法虽然简单,但是无法对instance对象做延迟加载,因为instance是static修饰的,所以当jvm加载类的时候就会常见instance对象,如果此时单例类中还有其他方法,在任何使用该单例类的时候就是加载instance对象,而不管instance方法是否被用到。
(2)懒加载及实现线程安全的单例模式
/**
* @author 江鹏飞
* 单例对象的延迟加载及线程安全实现
*/
public class LazySingleton {
private LazySingleton(){
System.out.println("lazySingleton is created!");
}
private static LazySingleton singleton = null;
public static synchronized LazySingleton getLazySingleton(){
if(singleton==null){
singleton = new LazySingleton();
}
return singleton;
}
}
这种方法解决了(1)中的延迟加载问题以及保证了线程安全(因为在不同线程调用getLazySingleton()时在一个线程创建对象前,另外一个线程调用的时候会误认为当前instance为空),这种方法虽然解决了上述问题,但是如果在代码中使用synchronized时在多线程环境会出现线程阻塞影响系统效率。显然这个也不是一个很好的实际方法。
(3)使用内部类的方式设计单例模式(推荐)
/**
* @author 江鹏飞
* 使用内部类的方式实现单例模式
*/
public class StaticSingleton {
private StaticSingleton(){
System.out.println("StaticSingleton is created!");
}
private static class SingletonHolder{
private static StaticSingleton instance = new StaticSingleton();
}
public static StaticSingleton getInstance(){
return SingletonHolder.instance;
}
}
这种方法解决了(2)中多线程环境下线程阻塞问题提高了系统的性能,使用内部类来维护单例的实例,当StaticSingleton 被加载时它的内部类并不会初始化。当StaticSingleton 被jvm加载时单例类SingletonHolder不会被初始化,而当调用 getInstance()方法时内部类才会被jvm加载从而初始化instance,因为实例对象的创建在类加载时完成,则天生对线程友好。getInstance()也不需要synchronize修饰。这实现方式同时具备以上两种实现的优点。
注意: 通常情况下用上面设计的单例方法可以确保系统中只存在一个实例,但是当通过反射机制,强行调用单例类的私有构造函数生成多个单例。
(4)序列化/反序列化的单例实现
package com.ycit.singleton;
import java.io.Serializable;
/**
* @author 江鹏飞
* 序列化反序列化单例模式的实现
*/
public class SerSingleton implements Serializable {
String name;
private SerSingleton() {
System.out.println("Singleton is created");
name="SerSingleton";
}
private static SerSingleton instance = new SerSingleton();
public static SerSingleton getInstance() {
return instance;
}
private Object readResolve(){
return instance;
}
}