在实际开发中,我们常会需要使用到单例模式。单例模式的核心就是,一个类只有一个实例。
如何实现只有一个实例呢?关键是:构造函数的私有化。
单例模式的实现有很多中,这里介绍一下常见的六种。
和其他介绍单例的不一样。我们首先介绍一种不常用的,但是我认为很有潜力,以后的单例实现最常用的方式。那就是使用枚举来实现单例模式。然后才是其他几种实现。上代码:
(1)枚举实现单例:
public enum Singleton {
INSTANCE;
public void showMessage(){
System.out.println("枚举");
}
}
是不是超简单?超级清晰?使用的时候直接Singleton.INSTANCE。就可以了。
因为这种方式在JDK1.5之后才支持,所以在一些老系统上可能不能用。但是现在JDK10都出来了,所以我认为以后这种方式会最常用。为什么:1.很简洁,甚至简单。2.自动支持序列化机制。3.绝对防止被多次实例化。4.线程安全。
Perfect!
(2)懒汉式线程不安全:
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance() {
if(null == instance) {
instance = new Singleton();
}
return instance;
}
}
很简单的一种单例模式,(当然,枚举更简单)很容里理解:静态私有的实体类,私有的构造方法,提供get方法,只需要在第一次调用的时候实例化一次。
但是缺点也很明显,线程不安全。多线程的情况下就不能正常工作了。
(3)懒汉式线程安全:
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(null == instance){
instance = new Singleton();
}
return instance;
}
}
和第二种方式的唯一区别就是:在get方法加了锁synchronized。这样就线程安全了。但是缺点也很明显,使用锁之后性能降低了。
(4)饿汉式:
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
饿汉式基于classloder的机制实现了线程安全。但是在类装载的时候就加载了实例,浪费内存,也不满足lazy loading的效果。
饿汉式和懒汉式可以见名知义地理解为:懒汉,他很懒,你不去找他他就不给你实例化。饿汉就是饿慌了,你不去找他他都给你实例化好了。
(5)双重校验锁:
public class Singleton {
private volatile static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(null == instance){
synchronized (Singleton.class) {
if (null == instance) {
instance = new Singleton();
}
}
}
return instance;
}
}
采用双锁机制实现单例,多线程下也保证安全和高效。但是呢,缺点也很明显:很复杂。至少对我来说,双重校验锁什么的根本不明白啊。照着写还行,要我解释就···弄不懂了。
(6)静态内部类:
public class Singleton {
private static class SingletonHolder{
private static final Singleton instance = new Singleton();
}
private Singleton(){}
public static final Singleton getInstance(){
return SingletonHolder.instance;
}
}
和双重校验锁一样的效果,但是简单一些。也是用classloder的机制实现线程安全。且类加载的时候不一定实例化单例。
总结:通常情况下,饿汉式的单例已经能满足日常使用了。有特殊需要的时候可以考虑双重校验锁。有反序列化创建爱你对象的需求的时候使用枚举。不过了,就个人而言,我更喜欢枚举的方式。正如前面所说:1.简洁。2.支持序列化。3.绝对单例。4.线程安全。Perfect!
差不多就是这样,希望大家能找到自己喜欢、工作适用的单例模式。
最后呢,作者水平有限,有什么问题大家可以提出来共同探讨学习。
差不多就是这样,祝大家学习愉快。谢谢。
—— by:轩辚 ——