<HeadFirst设计模式>笔记——单例模式

单例模式时比较常见的设计模式,它所解决的问题是:如何保证某个类的实例在全局只有唯一一个。
尽管实现起来比较简单,但要注意潜在的同步性问题。

单例模式特点

  1. 构造方法是私有的
  2. 要保证程序每次运行时只会创建一次这个类的实例
  3. 需要提供可以公开访问这个实例的方法

单例模式的典型例子

public class Singleton {

    static Singleton mInstance;

    private Singleton() {
        System.out.println("Singleton constructor");
    }

    public static Singleton getInstance() {

        if (mInstance == null) {
            mInstance = new Singleton();
        }
        return mInstance;
    }
}

问题

上面的代码暗藏了致命问题:在多线程处理中有可能会产生同步性的问题,导致实例化2次。
下面验证以下,先创建一个Thread类,run方法中获取Singleton实例并打印:

class MyThread extends Thread {
    int mId;

    public MyThread(int id) {
        mId = id;
    }

    @Override
    public void run() {
        System.out.println("Thread-" + mId + " running");
        System.out.println(mId + " getInstacne:" + Singleton.getInstance());
    }

}

执行代码如下:

public static void main(String[] args) {
        MyThread t1 = new MyThread(1);
        MyThread t2 = new MyThread(2);
        MyThread t3 = new MyThread(3);
        t1.start();
        t2.start();
        t3.start();
    }

重复运行几次,确实是有几率出现调用2次构造方法的问题,这无疑打破了原有的设计。

Thread-1 running
Thread-2 running
Singleton constructor
1 getInstacne:com.wils.pattern.singleton.Singleton@7dca373f
Singleton constructor
2 getInstacne:com.wils.pattern.singleton.Singleton@65c16078
Thread-3 running
3 getInstacne:com.wils.pattern.singleton.Singleton@65c16078

解决办法

有3种解决方案,各有优缺点,适用于不同情景。
1.将getInstance改成同步方法。
缺点:如果需要频繁调用,那么效率会很低。
优点:简单有效地解决问题。如果不考虑效率可以考虑这种方式。

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

2.将实例化提前到成员便利定义的时候。
缺点:造成创建和运行时方面的负担加重。
优点:简单有效,如果初始化负担不重可以使用。

public class Singleton {

    private static Singleton mInstance = new Singleton();

    private Singleton() {
        System.out.println("Singleton constructor");
    }

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

3.双重检查
缺点:不适用于java1.4及更早的版本。
优点:性能较好。

public class Singleton {
    //使用volatile
    static volatile Singleton mInstance;

    private Singleton() {
        System.out.println("Singleton constructor");
    }

    public static Singleton getInstance() {
        if (mInstance == null) {
            //加同步锁
            synchronized(Singleton.class){
                //再次检查
                if (mInstance == null) {
                    mInstance = new Singleton();
                }
            }
        }
        return mInstance;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值