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

Java设计模式之创建型模式-单例模式(Singleton)

2017-07-13 00:12 525 查看
单例模式(Singleton): 保证一个类仅有一个实例,并且提供一个访问它的全局访问点。

单例模式实现的三个基本步骤:

私有构造方法来限制外部类对其直接实例化

提供一个私有静态当前类的对象作为变量

提供一个公有静态方法返回类的实例

单例模式实现的几种方法:

懒汉式

  懒汉式单例模式在类创建的时候不创建实例,因此类加载的速度比较快。但是在运行时获取对象需要创建实例,此时速度相对较慢。换句话说,懒汉式单例模式在第一次调用的时候才初始化,这样做避免了内存的浪费。

  以下是使用此方法创建的LazySingleton类实例代码。

public class LazySingleton {

private static LazySingleton instance = null;

private LazySingleton() {

}

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


  这种方式在单线程的环境下可以很好的处理,但是在多线程的环境下,如果多个线程同时访问LazySingleton类,调用getInstance()方法时,多个线程会有可能获得单例类的不同实例从而破坏了单例模式。

  为了使上述方法变得线程安全,在多线程的环境下也满足我们的要求,现对类的全局方法进行同步处理,更改后的代码如下。

public class LazySingleton {

private static LazySingleton instance = null;

private LazySingleton() {

}

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


  上述两段代码的差异仅在于getInstance()方法是否有关键字synchronized修饰做同步处理来保证线程安全性。虽然说同步方法保证了线程安全性,但是你会发现我们每次调用一次getInstance()方法时都需要加锁一次,影响效率。

  为了避免每次的额外的开销,使用双重锁定,先看下代码的实现。

public class LazySingleton {

private static LazySingleton instance = null;

private LazySingleton() {

}

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


  这里做了两次instance == null的判断,有什么目的?

  第一次instance == null的判断可以避免线程每次都进行一次加锁,只是在实例未被创建的时候去进行加锁处理,减少开销。

  第二次instance == null的判断是为了防止多个线程同时调用getInstance()方法且都满足第一次instance == null的判断的这种情况,此时若没有第二次instance == null判断,所有线程排队进入锁区执行new LazySingleton()创建新的实例,达不到单例的要求。

饿汉式

  饿汉式单例模式正好与懒汉式单例模式相反,在类加载的时候就创建了实例,完成了初始化,所以类加载比较缓慢,而在运行时获取对象的速度相对较快。

  以下是使用此方法创建的LazySingleton类实例代码。

public class HungrySingleton {

private static HungrySingleton instance = new HungrySingleton();

private HungrySingleton() {

}

public static HungrySingleton getInstance() {
return instance;
}
}


  饿汉式单例模式相对比较常用,因为它不需要同步,执行的效率也相对较高。但是问题就是在类加载的时候就进行初始化,没有达到懒加载的效果,浪费内存。

  现在对如上代码做相应的调整。

public class HungrySingleton {

private static class HungrySingletonHolder {
private static final HungrySingleton INSTANCE = new HungrySingleton();
}

private HungrySingleton() {

}

public static final HungrySingleton getInstance() {
return HungrySingletonHolder.INSTANCE;
}
}


  在这个方法中,用一个私有内部的静态类来包含我们的单例类实例。当单例类加载的时候,HungrySingletonHolder类不会加载到内存当中,只有当我们调用getInstance()方法的时候,这个静态内部类才会被加载并且创建HungrySingleton类的实例。如果实例化很消耗资源,想让它延迟加载但又不希望在类加载的时候就实例化,那么这种方式就很合适。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: