java单例模式的5种实现方式

简介
单例模式是指在程序中只有一个实例存在。并且在程序运行中的任何时候都可以获取该实例对象。

场景
1.Android中数据库多线程读写时,保证每个线程使用同一个SQLiteDatabase对象,否则会报错“database is locked”;
2.Android常用框架EventBus中使用了单例模式。例如,当我们获取EventBus对象时,会使用的EventBus.getDefault(),当我们查看它的源码的时候,我们发现

    static volatile EventBus defaultInstance;
    ...//此处省略
    ...
    public static EventBus getDefault() {
        if (defaultInstance == null) {
            Class var0 = EventBus.class;
            synchronized(EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }

        return defaultInstance;
    }

也就是EventBus使用了双重校验锁的单例模式。此模式稍候介绍。

单例模式的实现方式

1.懒汉模式
特点:懒加载,不使用不创建,线程不安全

public class Singleton {
    private static Singleton mSingleton = null;

    private Singleton() {

    }

    public static Singleton getInstance() {
        if (mSingleton == null)
            mSingleton = new Singleton();
        return mSingleton;
    }

}

2.饿汉模式
特点:类加载的时候就创建对象,线程安全,没有懒加载的灵活性,可能造成内存浪费

public class Singleton {
    private static Singleton mSingleton = new Singleton();

    private Singleton() {

    }

    public static Singleton getInstance() {
        return mSingleton;
    }

}

3.双重校验锁
特点:可以保证线程安全,但是需要使用volatile(JDK1.5引入)修饰对象的引用,因为只是使用双重校验锁时,也不能保证它是一个线程安全的单例模式。因为JMM会有指令重排序机制。当我们创建一个对象的时候,JVM内部会将new Object()这条语句转化为若干指令,举例:
指令1:先为对象分配内存空间
指令2:初始化对象
指令3:设置对象所在的内存地址
以上是正常情况,如果发生了指令重排,可能指令3就会排在指令2的前面。
也就是先分配了内存地址,后初始化的对象。如果这时线程A指令执行的顺序是1-3-2,那么,当线程A执行到指令3的时候,mSingleton不为null了。如果线程B执行到第一个if判断的时候,发现mSingleton不为空,这时就会出现问题。(见下面代码)

public class Singleton {
    private static Singleton mSingleton = null;

    private Singleton() {

    }

    public Singleton getInstance() {
        if (mSingleton == null) {
            synchronized (Singleton.this) {
                if (mSingleton == null)
                    mSingleton = new Singleton();
            }
        }
        return mSingleton;
    }
}

使用volatile关键字后,就可以禁止指令重排序(增加了内存屏障)
正确代码:

public class Singleton {
    private volatile static Singleton mSingleton = null;

    private Singleton() {

    }

    public Singleton getInstance() {
        if (mSingleton == null) {
            synchronized (Singleton.this) {
                if (mSingleton == null)
                    mSingleton = new Singleton();
            }
        }
        return mSingleton;
    }
}

4.静态内部类
特点:类加载的时候就创建对象(此特点跟饿汉模式一样),线程安全;懒加载,不使用不创建,减少内存开销。

public class Singleton {

    private Singleton() {
    }

    private static class SingleInstance {
        private static final Singleton singleton = new Singleton();
    }

    public static final Singleton getInstance() {
        return SingleInstance.singleton;
    }
}

5.枚举单例模式
特点:线程安全,防止了反序列化重新创建的新对象

public enum  EmumSingleton {
    SINGLETON;

    EmumSingleton() {
    }

    public void doSomething(){
        System.out.println("单例模式");
    }
}

Over…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章