单例模式(Singleton Pattern)是一个比较简单的模式,它保证一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
通用代码:
<pre name="code" class="java"><span style="font-size:14px;">public class Singleton{
private static final Singleton singleton = new Singleton();
private Singleton(){}//私有构造函数,使其无法类外通过new构造
public static Singleton getSingleton(){
return singleton;
}
public static void doSomething(){}//类中其他方法,尽量为static
}</span>
单例模式通过private的构造函数确保只产生一个自行实例化的对象。
这种单例在类加载时就初始化单例,然而有时初始化单例代价比较高,希望在使用时才加载,这时可以使用Lazy loading方式的单例模式:
<pre name="code" class="java">public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
} <span style="font-family: Arial, Helvetica, sans-serif;"> </span>
<pre name="code" class="java"> public static void doSomething(){}//类中其他方法,尽量为static
}
这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。
单例模式在内存只有一个实例,减少了内存开销,也可以避免对资源的多重占用。不过单例模式一般没有抽象,扩展困难,而且也与单一职责原则冲突。
单例模式扩展,有上限多例模式:
<pre name="code" class="java">public class Singleton{
private static int manNum = 2;
private static ArrayList<Singleton> singleton = new ArrayList<Singleton>();
static{
for(int i = 0; i < manNum; i ++){
singleton.add(new Singleton());
}
private Singleton(){}//私有构造函数,使其类外无法通过new构造
public static Singleton getSingleton(int countNum){
return singleton.get(countNum);
}
public static void doSomething(){}//类中其他方法,尽量为static
}
使用单例模式需要注意JVM的
垃圾回收机制
,如果单例对象在内存中长久不使用,JVM就会认为这个对象是一个垃圾,在CPU资源空闲情况下会被清理掉,下次调用产生新的单例对象,如果单例类有状态值,则会出现异常。可以使用两种方法来避免:1.由容器管理单例的生命周期,如使用Spring可以使对象常驻内存。2.状态随时记录,使用异步记录的方法或观察者模式,保存状态的变化,确保单例重新初始化时可以获得销毁前数据。