Singleton, 单例模式: 顾名思义,就是只有一个实例。常见的实现方法有以下几种.
1. 懒汉
public class Singleton{
private static Singleton instance = null;
private Singleton(){
}
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
这种实现方式:
1. 非线程安全。并发情况下,可能有多个线程进入if语句块,从而创建了多个实例。
2. 节约内存空间。只有在调用getInstance()的时候才分配对象的空间。
3. 浪费时间。每次调用都要判断instance是否为空。
4. 初始化的时候比较快,而运行时比较慢。
5. 体现了延迟加载的思想。
6. 非线程安全问题,可以通过使用synchronized关键字来处理(后面还会讨论)
2. 饿汉
public class Singleton{
private static final Singleton instance = new Singleton();
private Singleton(){
}
public static Singleton getInstance(){
return instance;
}
}
这种实现方式:
1. 线程安全的。因为类加载的时候,instance对象只被初始化了一次,利用JVM类加载机制来保证线程安全。
2. 牺牲空间。加载类的时候,无论是否使用该类,都分配了内存空间。
3. 初始化的时候稍慢,但是运行时快。
4. 体现了缓存思想。
3. 双重检查加锁机制(对比并优化懒汉方法)
public class Singleton {
private volatile static Singleton instance = null;
private Singleton(){
}
public static Singleton getInstance(){
//先检查实例是否存在,如果不存在才进入下面的同步块
if(instance == null){
//同步块,线程安全的创建实例
synchronized (Singleton.class) {
//再次检查实例是否存在,如果不存在才真正的创建实例
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
这种实现方式:
1. 线程安全。
2. 加快运行速度。只是第一次创建实例的时候同步,以后都不用同步了。
3. 比在懒汉方式中加入synchronized方法效率高:(如下)
4. volatile修饰的变量值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存。
5. volatile关键字屏蔽掉了JVM中的一些必要的代码优化,所以可能降低一些运行效率(没有验证)。
public static synchronized getInstance(){
}
4. 更优解决方案
public class Singleton {
private static class Holder {
private static final Singleton instance = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return Holder.instance;
}
}
这种实现方法:
1. 使用静态内部类和缺省同步机制实现。
2. 缺省同步机制是指:JVM隐含的执行的同步,这里指静态初始化器(在静态字段或者static{}上的初始化 器)初始化的时候。
3. 类加载的时候并不会像饿汉一样初始化对象,而是在getInstance被调用之后才会。而且JVM保证了线程安 全问题。