单例设计模式是最简单的设计模式之一,这篇文章简单介绍单例设计模式作用,如何使用单例设计模式,以及一些简单的例子。
单例设计模式的作用
很多对象不需要重复创建回收,自始至终我们可以使用一个对象复用。单例设计模式就是为了防止对象的重复创建。
单例设计模式实现
饿汉式单例模式
为了使程序获取的都是同一个对象,那么可以使用静态对象的方式保证对象唯一,这就是饿汉式单例模式。
饿汉式单例模式足够简单,且线程安全,但是缺点也很明显,就是类加载的时候就会被初始化。
class Client{
private static Client c = new Client();
private Client(){}
public static Client getClient(){
return c;
}
}
懒汉式单例模式
由于饿汉式的缺点,懒汉式单例模式应运而生,让对象在使用的时候创建。
class Client{
private static Client c = null;
private Client(){}
public static Client getClient(){
return c;
}
}
很显然这种方式存在线程安全问题,无法完全保证对象唯一。
- 使用synchronized方法保证线程安全:
//懒汉式
class Client{
private static Client c = null;
private Client(){}
public static synchronized Client getClient(){
if (c = null){
c = new Client();
}
return c;
}
}
- 由于我们只需要在new的时候保证线程安全,所以可以使用二次判断做以下改进这样在getClient的大部分时候不需要进去synchronize中去,大大提高效率:
//懒汉式
class Client{
private volatile static Client c = null;
private Client(){}
public static Client getClient(){
if (c == null){
synchronized (Client.class){
if (c == null){
c = new Client();
}
}
}
return c;
}
}
IoDH(Initialization Demand Holder)单例模式
IoDH单例模式整合了懒汉式和饿汉式单例模式,是最完美的单例模式实现。
饿汉式单例模式是在静态变量初始化对象,那么在JVM加载这个类的时候就会初始化静态变量,所以饿汉式会在JVM加载时创建对象。而JVM加载对象是不会初始化静态内部类,利用这个特点就可以保留饿汉式的有点,又能够lazy加载。
class Client{
private Client(){}
public static Client getClient(){
return ClientHolder.c;
}
private static class ClientHolder{
private final static Client c = new Client();
}
}
枚举实现单例模式
在Effective Java中,作者极力推荐使用枚举实现单例模式。因为枚举拥有线程安全,写法简单等特点,并且java其他单例方式如果实现了序列化的接口就不能保证对象唯一。因为java序列化反序列化是通过反射实现的,反射是可以破坏私有构造函数的。而枚举不是通过反射进行序列化和反序列化的。
public class Client {
private Client(){}
private enum EnumHolder{
INSTANCE;
private final Client c;
EnumHolder(){
c = new Client();
}
private Client getClient(){
return c;
}
}
public static Client getClient(){
return EnumHolder.INSTANCE.getClient();
}
}