singleton

pulbic class Singleton {

    //Static variables are initialized only once when 
    //the Classloader load the class for the first time.
    private static Singleton instance = new Singleton();

    private Singleton() {}

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

上面代码就是单例模式最简单的实现方式,这种实现方式适合那些在初始化时就要用到单例的情况,这种方式简单粗暴,如果单例对象初始化非常快,而且占用内存非常小的时候这种方式是比较合适的,可以直接在应用启动时加载并初始化 —— Eager Instantiation

如果单例初始化的操作耗时比较长而应用对于启动速度又有要求,或者单例的占用内存比较大,再或者单例只是在某个特定场景的情况下才会被使用,而一般情况下是不会使用时,使用Eager Instantiation的单例模式就是不合适的,这时候就需要用到Lazy Instantiation的方式去按需延迟加载单例。如下代码:

pulbic class Singleton {
    private static Singleton instance;
    private Singleton() {}
    public static Singleton getInstance() {
        if (null == instance) {
            instance = new Singleton();
        }
        return instance;
    }
}

Eager InstantiationLazy Instantiation的最大区别就是将单例的初始化操作,延迟到需要的时候才进行,这样做在某些场合中有很大用处。比如某个单例用的次数不是很多,但是这个单例提供的功能又非常复杂,而且加载和初始化要消耗大量的资源,这个时候使用Lazy Instantiation就是非常不错的选择。

多线程下的单例模式
上面介绍了一些单例模式的基本应用方法,但是上面所说的那些使用方式都是有一个隐含的前提,那就是他们都是应用在单线程条件下,一旦换成了多线程就有出错的风险。
如果在多线程的情况下,Eager Instantiation不会出现问题,因为JVM只会加载一次单例类,但是Lazy Instantiation可能就会出现重复创建单例对象的问题。为什么会有这样的问题呢?因为Lazy Instantiation在创建单例时是线程不安全的,多个线程可能会并发调用他的 getInstance 方法导致多个线程可能会创建多份相同的单例出来。
那有没有办法,使Lazy Instantiation的单利模式也是线程安全的呢?答案肯定是有的,就是使用加同步锁的方式去实现。如下代码:

pulbic class Singleton {
    private static Singleton instance;
    private Singleton() {}

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

这种是最常见的解决同步问题的一种方式,使用同步锁 synchronized防止多线程同时进入造成instance被多次实例化。

有没有更好的实现方式呢?答案是肯定的。 我们可以利用JVM的类加载机制去实现。在很多情况下JVM已经为我们提供了同步控制,比如:在static{}区块中初始化的数据,访问final字段时等等。因为在JVM进行类加载的时候他会保证数据是同步的,我们可以这样实现:采用内部类,在这个内部类里面去创建对象实例。这样的话,只要应用中不使用内部类 JVM 就不会去加载这个单例类,也就不会创建单例对象,从而实现Lazy Instantiation的延迟加载和线程安全。如下代码:
静态内部类:

pulbic class Singleton {
    //内部类,在加载该内部类是才会去创建单例对象
    private static class SingletonHolder {
        public static Singleton instance = new new Singleton();
    }

    private Singleton() {}

    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
}

你真的会写单例模式吗——Java实现
singleton模式四种线程安全的实现

Java Singleton and Synchronization

静态内部类什么时候加载呢?
加载一个类时,其内部类是否同时被加载?引申出单例模式的另一种实现方式
静态内部类、静态变量的加载次数-理解静态内部类实现线程安全的单例模式
When is a static nested class (and static members therein) loaded into memory?
when static variables are initialized in Java
How static class variables get initialized

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值