转载自:
http://blog.csdn.net/caihaijiang/article/details/9154077
一、单例模式
单例模式:确保一个类只有一个实例,并提供一个全局访问点。
在java中实现单例模式,需要:私有的构造器、一个静态变量和一个静态方法。类图如下:
二、单例模式实现
实现方式一:不考虑多线程情况
- public class Singleton {
- private static Singleton uniqueInstance;
- private Singleton() {
- }
- public static Singleton getInstance() {
- if (uniqueInstance == null) {
- uniqueInstance = new Singleton();
- }
- return uniqueInstance;
- }
- }
public class Singleton {
private static Singleton uniqueInstance;
private Singleton() {
}
public static Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
该实现方式,在多线程的情况下,存在问题:会产生多个实例。实现方式二:考虑多线程,但牺牲了性能
- public class Singleton {
- private static Singleton uniqueInstance;
- private Singleton() {
- }
- public static synchronized Singleton getInstance() {
- if (uniqueInstance == null) {
- uniqueInstance = new Singleton();
- }
- return uniqueInstance;
- }
- }
public class Singleton {
private static Singleton uniqueInstance;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
跟实现方式一相比,getInstance方法使用synchronized进行了同步。这解决了多线程并发的问题,但是却因为同步而导致每次访问该方法,都付出了性能的代价(同步一个方法可能造成程序执行效率下降100倍)。当然,如果getInstance()的性能对应用程序不是很关键(例如访问次数很少),则可以采用这种方式,既简单又有效。如果性能是关键(例如该方法被频繁调用),则需要使用下面的两种方式来实现。
实现方式三:使用“急切”创建实例,而不用延迟实例化的做法(也称为“饿汉式”单例类,与其对应的是“懒汉式”单例类)
- public class Singleton {
- private static Singleton uniqueInstance = new Singleton();
- private Singleton() {
- }
- public static Singleton getInstance() {
- return uniqueInstance;
- }
- }
public class Singleton {
private static Singleton uniqueInstance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return uniqueInstance;
}
}
利用这个做法,我们依赖JVM在加载这个类时马上创建此唯一的实例。其缺点就是,没有延迟实例化,只要类被加载了,就创建实例,而不管后续是否使用该实例。
实现方式四:用“双重检查加锁”,在getInstance()中减少使用同步利用双重检查加锁,首先检查实例是否已经创建,如果未创建,则进行同步,然后再次判断是否已创建实例,如果没有,则创建。
- public class Singleton {
- private volatile static Singleton uniqueInstance;
- private Singleton() {
- }
- public static Singleton getInstance() {
- if (uniqueInstance == null) {
- synchronized (Singleton.class) {
- if (uniqueInstance == null) {
- uniqueInstance = new Singleton();
- }
- }
- }
- return uniqueInstance;
- }
- }
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {
}
public static Singleton getInstance() {
if (uniqueInstance == null) {
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
uniqueInstance,定义成volatile,确保实例化的过程中,多线程能够正确的处理该变量。
注意:双重检查加锁不适用于jdk 1.4及更早的版本。
三、JDK中单例模式的应用例子
JDK中的Java.lang.Runtime类,就是使用单例模式,而且使用的是上面介绍的第三种实现方式。如下:
- public class Runtime {
- private static Runtime currentRuntime = new Runtime();
- /**
- * Returns the runtime object associated with the current Java application.
- * Most of the methods of class <code>Runtime</code> are instance
- * methods and must be invoked with respect to the current runtime object.
- *
- * @return the <code>Runtime</code> object associated with the current
- * Java application.
- */
- public static Runtime getRuntime() {
- return currentRuntime;
- }
- /** Don't let anyone else instantiate this class */
- private Runtime() {}
- // 其他方法省略
- }
public class Runtime {
private static Runtime currentRuntime = new Runtime();
/**
* Returns the runtime object associated with the current Java application.
* Most of the methods of class <code>Runtime</code> are instance
* methods and must be invoked with respect to the current runtime object.
*
* @return the <code>Runtime</code> object associated with the current
* Java application.
*/
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
// 其他方法省略
}
四、小结
1、如果有两个及以上的类加载器,加载Singleton类,仍然会导致Singleton类被实例化出多个对象。所以,如果你的程序有多个类加载器,同时你又使用了单例模式,则需要小心这个问题。
2、单例模式是针对同一个JVM而言的,对于不同的JVM,每个JVM都会创建一个对应的实例。