您的位置 首页 java

Java单例不简单

今天给大家讲的一个设计模式是单例模式,它是一种广泛应用的设计模式,该模式的目的就是要保证在 JVM 中唯一实例的存在。比如我们常用的Spring开发框架,Spring Bean默认就是以单例形态存在于Spring容器中的。这个模式看似简单,但认真追究下去,其实没那么简单。单例模式有很多种写法,让我们来看一下:

一)饿汉模式

public class Singleton{

private static Singleton instance = new Singleton();

private Singleton(){}

public static Singleton getInstance(){

return instance;

}

}

饿汉模式在JVM加载Singleton时就会创建实例,生命周期跟随JVM,缺点是有点浪费内存空间;

接下来我们再看懒汉模式,

二)懒汉模式一(静态内部类)

public class Singleton{

private Singleton(){}

private static class SingletonHolder{

private static Singleton instance = new Singleton();

}

public static Singleton getInstance(){

return SingletonHolder.instance;

}

}

静态内部类模式和饿汉模式比,优势是只有在调用 getInstance ()方法时,类的唯一实例对象才创建,从而达到延迟加载的效果。

我们再看另外一种懒汉模式,

三)懒汉模式二(双重校验模式)

public class Singleton{

private static volite Singleton instance;

private Singleton(){}

public static Singleton getInstance(){

if(instance == null) {//语句1

sycnchrosized(Singleton.class) {//语句2

if(instance == null){//语句3

instance = new Singleton();//语句4

}

}

return instance;

}

}

其中,如果instance不声明volite类型,会由于 Java编译器 会进行指令重排,导致返回的instance在没有初始化的情况下被返回。怎么理解呢?假设有两个 线程 A和B,线程A先拿到了对象锁,执行到了语句4,这个语句实际是有以下三个原语组成:1、分配一块内存memory;2、在该内存上初始化Singleton对象;3、最后将该内存地址赋值给instance;但由于指令重排,会导致3在2前面先发生,此时线程B执行到语句1时,发现instance不为空,直接返回instance实例,但此实例是没经过初始化的,当访问instance的成员变量时,就有可能造成空指针异常;

最后一种创建单例的模式是枚举模式,这也是《Effective Java》作者推荐的一种方式,但实际工作中,很少有攻城狮使用此种方法。

四)枚举模式

public enum Singleton{

A;

public void someMethod(){

dosomething();

}

}

Singleton.A.someMethod();

总结如下:

单例的不同实现方式

留一个思考题给大家,上面提到的前三种单例模式,一定会保证JVM中是单例吗?

文章来源:智云一二三科技

文章标题:Java单例不简单

文章地址:https://www.zhihuclub.com/196681.shtml

关于作者: 智云科技

热门文章

网站地图