设计模式学习-单例模式
单例模式: 确保一个类只有一个实例,并提供一个全局访问点。
单例模式要素:
a)私有构造方法
b)私有静态引用指向自己实例
c)以自己实例为返回值的公有静态方法
一般要实现一个单例 最简单的方式:
public class SingleInstance {
private static SingleInstance instance;
private SingleInstance() {
}
public static SingleInstance getInstance() {
if (null == instance)
instance = new SingleInstance();
return instance;
}
}
但是这样会有一个问题,当多个线程同时调用 getInstance() 方法时,可能会产生多个instance 实例,因此这种方式并不是真正的单例。
为了解决线程安全问题,我们只需要在getInstance() 方法上使用synchronized 关键字给线程加锁即可。
public class SingleInstance {
private static SingleInstance instance;
private SingleInstance() {
}
public static synchronized SingleInstance getInstance() {
if (null == instance)
instance = new SingleInstance();
return instance;
}
}
synchronized 的作用是加锁,当多个线程同时调用getInstance() 时,只有一个线程能进入,其他线程会等待进入的线程出来之后在一一进入,这样就能保证instance 实例是唯一的。这才是真正的单例。
不过这并不是完美的解决方案,只要是锁,必然有性能损耗问题。而且对于上面的代码,其实我们只需要在线程第一次访问时加锁即可,之后并不需要锁,锁给我们带来了系统资源浪费。
上面两种方式都是在getInstance() 方法中创建实例,也就是说在要调用的时候才创建实例,这种方式被称为“懒汉式”,英文名,叫 lazy loading,也就是延迟加载。
新的解决方案是not lazy loading,在类加载时就创建好了实例:
public class SingleInstance {
private static SingleInstance instance = new SingleInstance();
private SingleInstance() {
}
public static SingleInstance getInstance() {
return instance;
}
}
这种方式就可以保证实例唯一。
除了上面的几种方式,还有一种叫 double-checked locking (双重检查加锁)
这种方式主要用到两个关键字volatile 和 synchronized,代码如下:
public class SingleInstance {
private volatile static SingleInstance instance;
private SingleInstance() {
}
public static SingleInstance getInstance() {
if (instance == null) {
synchronized (SingleInstance.class) {
if (instance == null) {
instance = new SingleInstance();
}
}
}
return instance;
}
}
volatile 关键字简单来说就是可以保证instance变量在被其中一个线程new出来时,其他线程可以立即看到结果并正确的处理它。
总结:感觉平时一般可以直接用
public class SingleInstance {
private static SingleInstance instance = new SingleInstance();
private SingleInstance() {
}
public static SingleInstance getInstance() {
return instance;
}
}
就可以满足需求了。ok 单例就说到这儿了,优点儿?
优点就是使用单例模式,对象在内存中只有一个实例,并且无需频繁的创建和销毁对象,大大的减少了性能的损耗。