单例模式Singleton 你是唯一

单例模式Singleton 你是唯一
单例模式:确保指定类有且只有一个对象,并提供一个全局的访问点。

1.单例模式(分为懒汉和饿汉)

 * 懒汉式,创建时判断对象实例为空,则创建
 * 
 * @author k
 * 
 */
public class SingleA {

    // 定义私有并静态的本类对象实例
    private static SingleA mInstance;

    // 私有化构造函数
    private SingleA() {

    }

    // 静态方法返回对象实例
    public static SingleA newInstance() {
        if (mInstance == null) {
            mInstance = new SingleA();
        }
        return mInstance;
    }
}
/***
 * 饿汉式单例模式
 * 
 * @author k
 * 
 */
public class SingleB {
    // 定义私有并静态的本类对象实例,并初始化
    private static SingleB mInstance = new SingleB();

    // 私有化构造函数
    private SingleB() {
    }

    // 静态方法返回对象实例
    public static SingleB newInstance() {
        return mInstance;
    }
}

上面两种方式的实现单例模式,总结:
1. 私有化构造函数
2. 定义私有并静态的类对象
3. 提供静态方法返回该对象

多线程下单例模式

懒汉模式中,每次newIntance创建时,会先判断对象是否为空,如果为空则会通过调用私有构造函数实例化对象并赋值。那么问题来了,如果在多线程中通过newIntance创建对象时,可能就出现线程1判断mInstance=null,在实例化对象并赋值之前,线程2也开始newIntance,线程2中 判断mInstance=null,则再次实例化对象并赋值,这种方式是线程不安全的,不满足单例模式有且只有一个对象的原则。
测试结果如下:

// 静态方法返回对象实例
    public static SingleA newInstance() {
        if (mInstance == null) {
            mInstance = new SingleA();
        }
        return mInstance;
    }
/***
*  多线程单例实例化测试
*/
private static void multipleThreadSingletonTest() {
        for (int i = 0; i < 1000; i++) {
            new Thread(new Runnable() {
                public void run() {
                    SingleA a = SingleA.newInstance();
                    System.out.println(a);
                }
            }).start();

            new Thread(new Runnable() {
                public void run() {
                    SingleA a = SingleA.newInstance();
                    System.out.println(a);
                }
            }).start();
        }
    }

观察打印结果:发现不止创建了一个对象

image

解决问题多线程不安全,采用线程同步锁即可解决该问题,改造后代码如下

// 静态方法返回对象实例,方法上synchronized同步锁
public static synchronized SingleC newInstance() {
    if (mInstance == null) {
        mInstance = new SingleC();
    }
    return mInstance;
}

测试发现newInstance方法上加上synchronized同步方法后,可以多线程下创建对象有且只有一个
缺点是:每次调用newInstance方法都进行同步,造成了不必要的开销,性能下降。

Double CheckLock单例模式

先判断实例对象是否为空,避免不必要的同步
在实例为null的情况下创建实例,使用synchronized同步,避免多线程不安全的问题

// Double CheckLock单例模式
public static SingleD newInstance() {
    if (mInstance == null) {// 先判断实例对象是否为空,避免不必要的同步
        synchronized (SingleD.class) {
            if (mInstance != null) {
                mInstance = new SingleD();
            }
        }
    }
    return mInstance;
}

静态内部类单例模式

上面Double CheckLock单例模式,可以解决多线程同步,性能问题,但小概率范围内也可能出现实例化失效的问题。

采用静态内部类的方式实现单例模式,看上去似乎更像“饿汉式”模式,实际上当第一次加载SingleE类是不会初始化mInstance,只有在第一次调用newInstance()方法是才会初始化,也就是只有在第一次调用newInstance()虚拟机才加载静态内部类SingleHoloder,这种方式线程安全,能保证对象的唯一性,推荐使用。


/***
 * 静态内部类单例模式
 * 
 * @author k
 * 
 */
public class SingleE {

    // 私有化构造函数
    private SingleE() {

    }

    // 静态内部类 创建
    public static class SingleHoloder {
        private static final SingleE mInstance = new SingleE();
    }

    public static SingleE newInstance() {
        return SingleHoloder.mInstance;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值