一、前言
单例模式是一种常用的软件设计模式,在它的核心结构中值包含一个被称为单例的特殊类,一个类只有一个实例,即一个类只有一个对象实例。该模式在Java和Android代码开发中很是常见,在面试过程中经常会被问到,我曾以该问题面试很多工作5年以上的同学,他们很难将问题答全,甚至连最基本的懒汉模式和恶汉模式也没能说出来,为此有必要总结一下。
二、单例模式
单例模式中分为懒汉模式和饿汉模式,关于这两种模式很多同学可能一时半会记得,但是时间长了就区分不清楚了,关于这两个名词可以这样理解。懒汉模式可比方成一个汉子,他比较懒,你不去叫唤他让他干啥,他是不会动弹的,放在单例模式的代码中就可以对应的这样理解了,如果不去使唤一个对象来完成某项功能,该对象也同样是懒得实例化的。
2.1 懒汉模式
以下便是最简单的懒汉模式,是非线程安全的,一般在代码中不会。
public class SingletonDemo {
private static SingletonDemo instance;
private SingletonDemo(){}
public static SingletonDemo getInstance(){
if (instance == null) {
instance = new SingletonDemo();
}
return instance;
}
}
为了保证懒汉模式单例的线程安全,常见的用法便是加锁,但是加锁的同时又要考虑到程序运行的效率,常用的懒汉模式的单例是加上双锁,代码如下:
public class SingletonDemo {
private volatile static SingletonDemo singletonDemo;
private SingletonDemo(){}
public static SingletonDemo getInstance(){
if (singletonDemo == null) {
synchronized (SingletonDemo.class) {
if (singletonDemo == null) {
singletonDemo = new SingletonDemo();
}
}
return singletonDemo;
}
}
这种懒汉模式便是常用的单例模式,针对这种双锁需要在JDK1.5之后才能达到双锁的效果,目前使用的JDK多是在JDK1.5版本以上。
2.2 饿汉模式
针对单例模式中饿汉模式,可以这般理解,饿汉好比一个饥饿的人,所以他会最大程度的消耗资源来满足的饥饿而不管他是否需要。放在单例模式的饿汉模式的代码实现中,饿汉模式会在代码的运行初期就将单例给实例化。
//第一种写法
public class SingletonDemo {
private static SingletonDemo instance = new SingletonDemo();
private SingletonDemo(){}
public static SingletonDemo getInstance(){
return instance;
}
}
//第二种写法
public class SingletonDemo {
private static SingletonDemo instance = null;
static{
instance = new SingletonDemo();
}
private SingletonDemo(){}
public static SingletonDemo getInstance(){
return instance;
}
}
以上两种单例模式都会在设计模式中有讲解到,用法也各有优劣,懒汉模式的优点便是在代码中没有单例的情况下,不会去加载单例类的资源不会造成资源的浪费。缺点也很明显,加锁同步会带来程序运行效率的损失。饿汉模式的优缺点恰好与懒汉模式相反,如果明确知道单例对象在程序代码中用的很频繁,就可以考虑使用饿汉模式了。
在除去懒汉模式和饿汉模式,《effective java》为我们提供了另外两种单例模式的实现方式,一种是通过静态内部类来实现,另一种便是通过枚举来实现。
内部类单例模式
private StaticInnerSingleton() {
if (SingletonHolder.instance != null) {
throw new IllegalStateException();//此处是避免单例被反射调用
}
}
private static class SingletonHolder {
private static StaticInnerSingleton instance = new StaticInnerSingleton();
}
public static StaticInnerSingleton getInstance() {
return SingletonHolder.instance;
}
}
静态内部类兼顾了懒汉模式和恶汉模式的优点,但是又避免了它们缺点,是《effective java》比较推崇的一种单例模式的实现。
枚举单例模式
public enum SingletonDemo6 {
instance;
public void whateverMethod(){
}
}
《effetive java》的作者同样很推崇这种实现方式,这种方式线程安全,且不能够被反射,但是奈何这种方法用的还是比较少,不是很常见。