设计模式:单例模式

一、定义

保证这个程序中只有一个实例

二、基本写法

  1. 构造函数私有,防止外部new对象
  2. 内部提供一个静态方法,让外部调用

饿汉式

//单例模式 -- 饿汉式
public class Singleton {
    //随着对象的创建就去new 
    private static Singleton mInstance = new Singleton();

    private Singleton() {
    }

    public static Singleton getInstance(){
        return mInstance;
    }
}

懒汉式

初始样式

//单例模式 -- 懒汉式
public class Singleton {
    //只有使用的时候才去new对象,更加高效,
    private static Singleton mInstance ;

    private Singleton() {
    }

    
    public static Singleton getInstance(){
        if (mInstance == null){
            //会出现多线程并发问题
            mInstance = new Singleton();
        }
        return mInstance;
    }
}

解决懒汉式在多线程下的并发问题

//单例模式 -- 懒汉式
public class Singleton {
    private static Singleton mInstance;

    private Singleton() {
    }

    //解决懒汉式多线程并发问题,但是会出现效率低的问题,每次获取都要经过同步锁的判断
    public static synchronized Singleton getInstance(){
        if (mInstance == null){
            mInstance = new Singleton();
        }
        return mInstance;
    }   
}

解决每次获取都要经过同步锁判断导致的线程低的问题  -- 双重检验

//单例模式 -- 懒汉式
public class Singleton {
    private static Singleton mInstance;

    private Singleton() {
    }

   //既保证了线程安全,效率也是比较高,但是会出现指令重排序问题
    public static Singleton getInstance() {
        if (mInstance == null) {
            synchronized (Singleton.class) {
                if (mInstance == null) {
                    mInstance = new Singleton();
                }
            }
        }
        return mInstance;
    }
}

解决指令重排序问题 -- 加volatile关键字

//单例模式 
public class Singleton {
    private static volatile Singleton mInstance;

    private Singleton() {
    }
    public static Singleton getInstance() {
        if (mInstance == null) {
            synchronized (Singleton.class) {
                if (mInstance == null) {
                    mInstance = new Singleton();
                }
            }
        }
        return mInstance;
    }
}

指令重排序问题分析:

Singleton mInstance = new Singleton();

在创建一个对象时,会经历以下几个步骤:

  1. 开辟一块新的内存空间
  2. 初始化对象
  3. 给变量赋值,也就是指向内存地址

在Java对线程中,2和3的执行的顺序是不固定的,也就是Java的指令重排序

当以上步骤3先于步骤2执行时,就会先将变量赋值,也就是新开辟的内存地址,这时调用者去拿mInstance时是不为空的,但是又没赋值,所以会出现问题

每个线程都有自己的线程工作区,一个线程修改了公用对象,可能对其他线程是不可见的,修改只适用于自己的线程工作区

解决办法:加上volatile关键字,禁止重排序,保证可见性

三、开发中用到的单例

Activity管理类

public class ActivityManager {
    private static volatile ActivityManager mInstance;
    private Stack mActivities;

    private ActivityManager(){
        mActivities = new Stack<>();
    }

    public static ActivityManager getInstance() {
        if (mInstance == null) {
            synchronized (ActivityManager.class) {
                if (mInstance == null) {
                    mInstance = new ActivityManager();
                }
            }
        }
        return mInstance;
    }

    /**
     * 添加统一管理
     * @param activity
     */
    public void attach(Activity activity){
        mActivities.add(activity);
    }

    /**
     * 移除解绑 - 防止内存泄漏
     * @param detachActivity
     */
    public void detach(Activity detachActivity){
        int size = mActivities.size();
        for (int i = 0; i < size; i++) {
            Activity activity = mActivities.get(i);
            if (activity == detachActivity) {
                mActivities.remove(i);
                i--;
                size--;
            }
        }
    }

    /**
     * 关闭当前的 Activity
     * @param finishActivity
     */
    public void finish(Activity finishActivity){
        int size = mActivities.size();
        for (int i = 0; i < size; i++) {
            Activity activity = mActivities.get(i);
            if (activity == finishActivity) {
                mActivities.remove(i);
                activity.finish();
                i--;
                size--;
            }
        }
    }

    /**
     * 根据Activity的类名关闭 Activity
     */
    public void finish(Class activityClass){
        int size = mActivities.size();
        for (int i = 0; i < size; i++) {
            Activity activity = mActivities.get(i);
            if (activity.getClass().getCanonicalName().equals(activityClass.getCanonicalName())) {
                mActivities.remove(i);
                activity.finish();
                i--;
                size--;
            }
        }
    }

    /**
     * 退出整个应用
     */
    public void exitApplication(){

    }

    /**
     * 获取当前的Activity
     * @return
     */
    public Activity currentActivity(){
        return mActivities.lastElement();
    }
}

四、Android源码中的单例

ActivityManager

你可能感兴趣的:(设计模式,单例模式,设计模式,java)