目的
确保一个类只有一个实例,并且提供一个全局访问点。
说明
例子
只有一个象牙塔可以让巫师学习他们的魔法。巫师总是使用同样的魔法象牙塔。这个象牙塔就是单例。
简单的说
确保只创建一个特定类的一个对象。
维基百科
在软件工程中,单例模式是一种软件设计模式,它将一个类的实例化限制为一个对象。对于需要确切的一个对象来协调系统中的操作时是非常有用的。
代码示例
实现单例的最好方式就是单个元素的枚举类
public enum EnumIvoryTower {
INSTANCE;
}
EnumIvoryTower enumIvoryTower1 = EnumIvoryTower.INSTANCE;
EnumIvoryTower enumIvoryTower2 = EnumIvoryTower.INSTANCE;
assertEquals(enumIvoryTower1, enumIvoryTower2); // true
复制代码
恶汉式单例模式
public final class IvoryTower {
/**
* 私有构造器,所以外部无法实例化该类
*/
private IvoryTower() {}
/**
* 静态实例.类加载完之后被实例
*/
private static final IvoryTower INSTANCE = new IvoryTower();
/**
* 调用此方法获取单例.
*
* @return 单例.
*/
public static IvoryTower getInstance() {
return INSTANCE;
}
}
复制代码
懒汉式单例
在Java中Initialize-on-demand-holder idiom 创建懒加载单例是一种安全的方式。当getInstance()调用时,内部类还没有被加载。而类加载是安全的,因此,这种解决方案是线程安全的,尽管没有使用volatile或者synchronized。
public final class InitializingOnDemandHolderIdiom {
/**
* 私有构造器.
*/
private InitializingOnDemandHolderIdiom() {}
/**
* @return 单例
*/
public static InitializingOnDemandHolderIdiom getInstance() {
return HelperHolder.INSTANCE;
}
/**
* 提供懒加载单例
*/
private static class HelperHolder {
private static final InitializingOnDemandHolderIdiom INSTANCE =
new InitializingOnDemandHolderIdiom();
}
}
复制代码
线程安全懒汉单例
实例被懒加载,因此需要同步机制。
public final class ThreadSafeLazyLoadedIvoryTower {
private static ThreadSafeLazyLoadedIvoryTower instance;
private ThreadSafeLazyLoadedIvoryTower() {
//防止被反射
if (instance == null) {
instance = this;
} else {
throw new IllegalStateException("Already initialized.");
}
}
/**
* 当第一次调用时实例才会被创建,但是由于每次调用都有锁,性能不好
*/
public static synchronized ThreadSafeLazyLoadedIvoryTower getInstance() {
if (instance == null) {
instance = new ThreadSafeLazyLoadedIvoryTower();
}
return instance;
}
}
复制代码
线程安全双重检查单例
public final class ThreadSafeDoubleCheckLocking {
//内存可见,防止重排
private static volatile ThreadSafeDoubleCheckLocking instance;
/**
* 私有构造防止被外部实例化
*/
private ThreadSafeDoubleCheckLocking() {
// 防止被反射
if (instance != null) {
throw new IllegalStateException("Already initialized.");
}
}
/**
* 公共访问
*
* @return 实例
*/
public static ThreadSafeDoubleCheckLocking getInstance() {
ThreadSafeDoubleCheckLocking result = instance;
// 检查是否被实例化,如果已经实例化则返回实例
if (result == null) {
// 有可能在其它线程初始化了
// 所以为了确保我们需要锁定一个对象来实现互斥。
synchronized (ThreadSafeDoubleCheckLocking.class) {
// 再次将实例赋值给局部变量以检查它是否被其他线程初始化
// 而当前线程被阻止进入锁定区域. 如果它已被初始化,那么我们可以返回之前创建的实例,就像之前的空检查一样。
result = instance;
if (result == null) {
//实例还是没有被创建(其它线程无法进入),所以我们可以安全地创建实例并且赋值给instance和result。
instance = result = new ThreadSafeDoubleCheckLocking();
}
}
}
return result;
}
}
复制代码
典型用例
- the logging class
- managing a connection to a database
- file manager