在23中设计模式中,单利模式使我们最先接触的,也是我们经常使用的一种设计模式。
设计模式就是指在整个程序运行中,有且只有一个实例存在。
1.简易实现
设计单利模式,我们会首先将构造方法私有化,保证外部无法调用构造方法创建对象。然后对外抛出一个静态方法获取实例。
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton() {
}
private static Singleton getInstance() {
return singleton;
}
}
2.延迟加载
虽然我们实现了单例模式,可是却存在一个问题,因为静态实例不管你是否调用 getInstance()
方法都会创建。如果程序中这样的单例很多,并且还没有被调用,将会无端的浪费很多资源。
public class Singleton {
private static Singleton singleton = null;
private Singleton() {
}
private static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
方法同步
先不初始化静态实例,在调用 getInstance()
方法中,先判断实例是否为空,然后再创建实例,这样就解决了无端浪费资源的问题。
这样的实现方式在单线程中运行没有问题,如果放在多线程的运行条件下,就会有一些隐藏的问题出现。我们在创建实例的时候,如果实例还没有创建,其他线程也在运行,当它判断实例是否为空时,此时实例还没有创建,他就会重复创建实例,导致一些隐藏的问题。
public class Singleton {
private static Singleton singleton = null;
private Singleton() {
}
private synchronized static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
代码块同步
虽然解决了多线程问题,但是在方法这里写代码片
加上 synchronized
关键字将比原始方法在效率上低好多。
public class Singleton {
private static Singleton singleton = null;
private Singleton() {
}
private static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
volatile关键字
代码块同步就比方法同步在效率上高很多。多线程有许多的未知性,除了重复创建实例这种情况,还有另外一种情况也有可能发生,尽管概率很小。
创建实例的需要两个步骤来执行。1.分配内存,将引用指向分配的内存地址。2.在内存中进行初始化操作。这两个步骤的顺序并没有明确定义,所以有一种可能,是先分配了内存地址将引用指向该地址,还没有进行初始化操作。此时若有线程判断实例是否为空,因为引用已经指向了内存地址,所以不为空,此时操作实例也会有一些隐藏的问题。
public class Singleton {
private volatile static Singleton singleton = null;
private Singleton() {
}
private static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}