什么是设计模式?其实简单的理解就是前人留下来的一些经验总结
一、懒汉式
懒汉式的特点就是在getInstance()方法时候才进行初始化
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
这种单列模式在线程并发时候就可能会产生多个实例,称为线程不安全
二、懒汉式(线程安全)
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
可以看出加入同步关键字synchronized
这样实现了线程的安全,但是每次调用都会实现同步,导致效果很低
三、双重检测机制
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if(instance==null){
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
二次检查实例是否创建,第一次检查没有创建,进行同步,同步后第二次检查,这种方法看似很完美,不过也有缺点,在于instance = new Singleton();这条语句,新建对象包含了下面三个步骤:
1、分配内存
2、执行构造方法的初始化
3、将对象指向分配的内存空间
由于java编译器为了尽可能减少内存操作速度远慢于CPU运行速度所带来的CPU空置的影响,虚拟机会按照自己的一些规则将程序编写顺序打乱——即写在后面的代码在时间顺序上可能会先执行,而写在前面的代码会后执行——以尽可能充分地利用CPU就会出现指令重排序(happen-before),从而导致上面的三个步骤执行顺序发生改变。正常情况下是123,但是如果指令重排后执行为1,3,2那么久会导致instance 为空,进而导致程序出现问题。解决方法呢?java中有一个关键字volatile,有一个作用就是防止指令重排。
private static Singleton instance;
饿汉式
饿汉式的特点就是在类加载的时候就进行初始化操作
public class Singleton{
private static final Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance(){
return instance;
}
}
与懒汉式相比,它是线程安全的,无需用同步关键字修饰
优点就是由于没有加锁,执行效率比较高
缺点就是在类加载时就初始化,会浪费内存