一、简介
单例模式是一种创建模式,这个模式能够确保该模式的类只有一个实例化的对象,并且外部只能通过该类获取其自身创建的实例化对象,而不能够在外部创建该类的实例化对象。
其具有以下4个特点:
- 只能有一个实例。
- 必须自己自己创建自己的唯一实例。
- 必须给所有其他对象提供这一实例。
- 构造方法是私有的。
单例模式的UML类图
二、单例模式的实现方式
单例模式有很多种实现的方式,这里介绍三种最常见的方式:饿汉式、懒汉式以及双重校验锁式。
1. 饿汉式
所谓饿汉式,其实就是不管你有没有使用这个对象,都先将这个对象实例化。其实现非常的简洁,Java代码如下
package singleton;
public class SingleObject {
private static SingleObject instance = new SingleObject();
private SingleObject(){}
public static SingleObject getInstance(){
return instance;
}
}
关键点在于私有化构造方法,如此在外部就无法创建该类的实例化对象。
2. 懒汉式
所谓懒汉式,就是在你需要使用该对象时,才创建该对象,一定程序上避免了饿汉式创建模式下产生的资源浪费。其实现也十分简洁,Java代码如下
package singleton;
public class SingleObjectLazy {
private static SingleObjectLazy instance;
private SingleObjectLazy(){}
public synchronized static SingleObjectLazy getInstance(){
if (instance == null) {
instance = new SingleObjectLazy();
}
return instance;
}
}
与饿汉式相比,只有在外部调用getInstance()方法时,instance才会创建,并且使用了synchronized关键字加了线程锁,保证了即使在多线程模式下获取到的对象也是单例的。
3. 双重校验锁式
双重校验锁式是为了解决懒汉式中过于频繁加锁的问题,通过单例模式的概念可以知道,在单例模式中,对象只创建一次,因此,没有必要每次调用getInstance()方法都对该方法加锁。
package singleton;
public class SingleObjectDCL {
private static SingleObjectDCL instance;
private SingleObjectDCL(){}
public static SingleObjectDCL getInstance() {
if (instance == null){
synchronized (SingleObjectDCL.class){
if (instance == null)
instance = new SingleObjectDCL();
}
}
return instance;
}
}
该方式实现的单例模式,仅在instance==null时进行加锁,相比于普通的懒汉式,大大减少了加锁的次数,因此提升了在多线程环境下getInstance()方法的运行性能。
一个简单的测试
package singleton;
public class Client {
public static void main(String[] args) {
SingleObject singleObject = SingleObject.getInstance();
singleObject.sayHai();
SingleObjectLazy singleObjectLazy = SingleObjectLazy.getInstance();
singleObjectLazy.sayHai();
SingleObjectDCL singleObjectDCL = SingleObjectDCL.getInstance();
singleObjectDCL.sayHai();
}
}
注:sayHai()方法是为了测试加上去的,与单例模式无关,因此没有在单例类代码中体现。