意图
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
例子
|
这里需要注意的一点就是构造函数使用了访问权限private修饰,表示别的地方无法构建该对象,除了他自己。
另外由于多线程安全问题,这里一般推荐下面的写法:public class World {
private static final World world;
private World() {
}
public static World getInstance() {
synchronized(World.class) {
if (world == null) {
synchronized(World.class) {
world = new World();
}
}
}
return world;
}
}
适用性
- 当类只能有一个实例而且客户可以从一个众所周知的访问点访问他
- 当这个唯一实例应该是通过子类化可扩展的,而且客户应该无需更改代码就能使用一个扩展的实例
结构
协作
客户只能通过Singleton的Instance操作访问一个Singleton的实例。
效果
Singleton模式有许多优点:
- 对唯一实例的受控访问。因为Singleton类封装它的唯一实例,所以它可以严格的控制客户怎样以及何时访问它。
- 缩小名空间。Singleton模式是对全局变量的一种改进。它避免了那些存储唯一实例的全局变量污染名空间。
- 允许对操作和表示的精化。Singleton类可以有子类,而且用这个扩展类的实例来配置一个应用是很容易的。你可以用你所需要的类的实例在运行时刻配置应用。
- 允许可变数目的实例。这个模式使得你易于改变你的想法,并允许Singleton类的多个实例。此外,你可以用相同的方法来控制应用所使用的实例的数目。只有允许访问Singleton实例的操作需要改变。
- 比类操作更灵活。
几种单例
1.静态参数
|
2.懒汉模式(线程不安全)
|
当需要,就创建;不需要,就为空。
3.懒汉模式(线程安全)
|
增加synchronized
锁完成现场安全。但是访问都会被锁占用资源。
4.饿汉模式(线程安全)
|
可以看到与1初始化一致,因此每次程序在打开时就会初始化,如果初始化过多导致打开卡顿。
5.使用类的内部类(线程安全)
|
仅在需要使用单例时调用getInstance进行单例的创建,同时不会因为加锁而增加性能消耗。
Java 加载外部类的时候,不会创建内部类的实例,只有在外部类使用到内部类的时候才会创建内部类实例。
6.双重锁校验(线程安全)
|
锁上提供了优化。
7.Atomic(线程安全)
Atomic原子类就是利用自旋CAS来保证线程安全的。public class Signleton {
private static final AtomicReference<Signleton> INSTANCE = new AtomicReference<Signleton>();
private static Signleton instance;
private Signleton() {}
public static Signleton getInstance() {
for ( ; ; ) {
Signleton instance = INSTANCE.get();
if (instance != null) return instance;
INSTANCE.compareAndSet(null, new Signleton());
return INSTANCE.get();
}
}
}
8.Effective Java作者推荐的枚举单例例(线程安全)
|