您的位置:首页 > 编程语言 > Java开发

Java设计模式之单例模式

2016-02-01 10:27 435 查看
单例模式是Java设计模式中的创建型模式,也是一种很常用的设计模式。单例模式主要是为了保证应用程序中的某个实例有且只有一个,因为在某些应用场景下,一些对象只要有一个就可以了,如线程池、缓存、日志对象等。常见的单例模式有饿汉模式和懒汉模式。

1.饿汉模式

饿汉模式使用下面的步骤创建一个单例模式类:

(1)将构造方法私有化,不允许外部直接创建对象;

(2)创建类的唯一实例,使用private static 关键词修饰;

(3)提供一个用于获取实例的方法,使用public static关键词修饰,供外部使用;

下面就是主要代码:

public class Singleton1 {
private Singleton1(){}

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


在饿汉模式中,我们在类的加载过程中实例化对象,因此如果实例化对象很复杂的话,会导致类的加载过程很慢。不过,由于在类的加载中实例化对象,因此恶汉模式获取对象很快,也是线程安全的。

2.饿汉模式的变种

在加载类的过程中,可以使用静态代码块对对象实例化,原理上还是一样。代码如下:

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


3.懒汉模式

懒汉模式主体思想和饿汉模式相似,不同的是懒汉模式在第一次调用的时候进行实例化,而恶汉模式在类加载的时候进行实例化。代码如下;

public class Singleton3 {
private Singleton3() {}

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


懒汉模式和恶汉模式相比,由于在第一次调用的时候进行实例化,因此类的加载速度比较快,不过获取对象时由于要判断并进行实例化,因此没有饿汉模式快。同时,这种模式也不是线程安全的,当两个线程同时获取对象的时候可能会出错。

4.懒汉模式(方法同步)

为了实现线程安全,可以加上synchronized关键字。用它来修饰一个方法或一个代码块的时候,可以保证同一时刻只有一个线程执行该段代码。代码如下:

public class Singleton4 {
private Singleton4() {}

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


5.懒汉模式(双重检查锁定)
双重检查锁定就是在getInstance()方法内部再使用synchronized关键字修饰,进行双重检查。代码如下:

public class Singleton5 {
private Singleton5() {}

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


6.懒汉模式(静态内部类)

public class Singleton6 {
private static class SingletonHolder {
private static final Singleton6 INSTANCE=new Singleton6();
}
private Singleton6() {}
public static final Singleton6 getInstance() {
return SingletonHolder.INSTANCE;
}
}


这种方式使用了classloader的机制来保证初始化instance时只有一个线程,它跟第1种和第2种方式不同的是(很细微的差别):第1种和第2种方式是只要Singleton类被装载了,那么instance就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。想象一下,如果实例化instance很消耗资源,我想让它延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这个时候,这种方式相比第1和第2种方式就显得很合理。

下面使用下面的代码简单测试一下:

public class test {
public static void main(String[] args) {
Singleton1 s1=Singleton1.getInstance();
Singleton1 s2=Singleton1.getInstance();
if(s1==s2)
System.out.println("s1和s2是同一个对象");
else
System.out.println("s1和s2不是同一个对象");
}
}


结果如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: