由Spring单例想到的

大家知道,在Spring和Struts整合的配置文件中,如果Bean实例的scope属性没有专门指定的话,则默认是单例模式。而且,Spring也推荐所有的业务逻辑组件、DAO组件、数据源组件等都配置成单例模式,因为这些组件无须保存任何用户状态,所有的客户端请求都可以共享这些业务逻辑组件、DAO组件。其实,很多java开发者,对这个单例的理解只知道,如果系统只需要一个类的实例就可以使用单例,当时我在这里,就存在疑问,疑问的理由是:比如一个业务逻辑组件类对象如果是单例模式,那么当同时被多个Action调用的时候,会不会发生冲突呢?比如都调用这个实例的某个方法,而这个方法又引用了一个这个类对象的成员变量。当时由于忙,没有顾上研究这个,这次过年在家时,搞清楚了这个问题。

       首先,我们要清楚java中的内存情况,大略如下,这个大家一般都知道:

       1:heap,堆内存,用来存放新创建的类对象,其实就是存储对象的成员变量值、变量类型、对象类型标记;2:stack,栈内存,用来存储局部变量、对对象的引用等;3:data segment,数据区,在这个区主要存放的是静态常量,和字符串常量。在类一开始被加载的时候此常量就被初始化放在这个区内,而且被全局所共享,所有的访问直接指向他即可。4:code segment,代码区,它是存放代码的区,所有的执行代码(其实就是函数)都放在此区内。通过对象的调用指向此区。

       大家都知道,类的方法在内存中只保存一份。系统将整个程序运行时所需要的数据空间安排在一个栈中(我们可以考虑是不是针对某个进程或者线程一级进行分配的),每调用一次方法(或者说调用一次函数)时,就在它在栈顶分配一个存储区,每当一个函数退出时,就释放它的存储区,则当前正在运行的函数的数据必然在栈顶。那么,当我们调用业务层的方法时,每次调用应该都会为局部变量重新分配栈,那么调用之间就不会有冲突。而在单例模式下,成员变量只保存了一份在heap中,如果方法调用中涉及到使用基本类型的成员变量,很有可能就造成了冲突(如果是对象类型的成员变量,则它的定义方法同样也不能如此),而且我做了实验,这个成员变量的确是只有一份,因此我觉得在定义方法时,这点是需要重视的地方。

       那么至此就解开了我的那个疑团。其实我们要清楚,最终程序都要解释成:“操作码+操作数”的形式。在方法调用时,:方法本身是操作码部分,保存在stack中,方法内部变量做为操作数根在操作码之后,如果是简单类型则保存在栈中,如果是对象类型的成员变量则保存的是对象在heap中的地址。再进一步想,程序代码的本质就是对内存的操作,这句话现在看起来简单,但是真要自己总结出来,还不是很容易。

       最后,我发现其实对这个知识点存在疑团究其原因是对底层东西的生疏。Java程序包装了C++的东西,为程序开发带来了便利,也让我们对底层的东西更加疏远,我们要尽量去拉近这个距离,对写出高质量才程序以及对新知识的理解,能起到促进作用。

猜你喜欢

转载自hcty31.iteye.com/blog/1047768