单例模式:
无论在什么时候,该类只有一个实例。
实现单例模式的要点就是提供一个私有的无参构造函数。
一、饿汉单例模式
饿汉就是很急迫的意思,可以想象一下一个饿了五六天的人看到面前放着一个美味的汉堡时的心情。即在类加载的时候就new一个实例,也称立即加载。
代码实例:
public class SingleObject {
private static SingleObject object = new SingleObject();
private SingleObject(){ }
public static SingleObject getInstance() {
return object;
}
}
二、懒汉单例模式
懒汉的意思就是慢悠悠的,不着急,也就是在调用方法的时候实例化对象,称为延迟加载。
public class SingleObject2 {
private static SingleObject2 object ;
private SingleObject2(){ }
public static SingleObject2 getInstance() {
if (object!=null) {
}else {
object = new SingleObject2();
}
return object;
}
}
在多线程环境下,上述的单例模式会出现多个实例,违背了单例模式的设计思想。那么该如何解决这个问题呢?大家首先想到的肯定是给getInstance()方法加上synchronized关键字,这样整个方法都上锁了,效率非常低。
public synchronized static SingleObject2 getInstance() {
if (object!=null) {
}else {
object = new SingleObject2();
}
return object;
}
尝试同步代码块呢?
public static SingleObject2 getInstance() {
synchronized (SingleObject2.class) {
if (object!=null) {
}else {
object = new SingleObject2();
}
}
return object;
}
此方法的运行效率也是非常低的,和sychronized同步getInstance()方法一样是同步运行的。
如果对部分关键代码上锁呢?
public static SingleObject2 getInstance() {
if (object!=null) {
}else {
synchronized (SingleObject2.class) {
object = new SingleObject2();
}
}
return object;
}
运行多线程测试,将发现会出现多个实例,是线程不安全的单例模式。
最后,对于上面的代码,可以使用DCL双重检查机制实现多线程环境下的延迟加载的单例模式。
public static SingleObject2 getInstance() {
if (object != null) {
} else {
synchronized (SingleObject2.class) {
if (object == null) {
object = new SingleObject2();
}
}
}
return object;
}
三、静态内置类实现单例模式
DCL可以解决多线程下懒汉单例模式的非线程安全问题,使用静态内部类可以达到同样的效果。
public class SingleObject3 {
private SingleObject3(){ }
private static class SingleFactory{
private static SingleObject3 object = new SingleObject3();
}
public static SingleObject3 getInstance(){
return SingleFactory.object;
}
}
四、静态代码块实现单例模式
静态代码块在类加载的时候就会被初始化,因此可以使用该特性实现单例模式。
public class SingleObject4 {
private SingleObject4() {}
private static SingleObject4 object = null;
static {
object = new SingleObject4();
}
public static SingleObject4 getInstance() {
return object;
}
}
五、使用enum实现单例模式
枚举和static代码块的特性相似,在使用枚举类时,会自动调用构造方法。
public enum EnumSingel {
SINGLE;
private Object object;
private EnumSingel(){
object = new Object();
}
public Object getInstance() {
return object;
}
}
只需要调用枚举实例然后再调用getInstance()即可;
EnumSingel.SINGLE.getInstance();