1.servlet为什么不是线程安全的?
例子:
…….
public int count = 0 ;
doPost(){}
doGet(){}
……
相信面试的时候除了问servlet的生命周期外,肯定会问到servlet是不是线程安全的?
不是线程安全,servlet本身设计是单实例多线程的。既然是多线程肯定会涉及到线程安全!
如上实例变量count为实例变量,就不是安全的,多线程读写过程中就会出错。
那么问题转化为为什么实例变量在多线程中不安全?(不加锁)。如果把count放在方法中是否是线程安全呢?回答是是的。
关于如何设置servlet为线程安全有哪些方法,生命周期,以后专门会学习,在此不在叙述。
2.jvm的基本内存模型
基于jdk1.6的jvm内存模型。
java堆
存放实例信息:比如类的信息,实例变量信息。
存放数组。
多线程共享内存
java虚拟机栈
存放基本数据类型的变量,对象的引用
线程私有。
方法区
类实例的方法信息
常量池:静态常量
本地方法区
调用本地计算机其他函数,比如arraylist的实现中调用本地操作数组方法copyArray
寄存器,等。
简单的概述如上,那么例子中count应该存放在堆中,多线程数据共享区域,很明显当多个线程同时修改和读取的时候肯定就会达不到预期效果。
3.java类的加载过程
我们在来看一个类的加载过程和内存区域划分。
加载,链接(验证,准备,解析),初始化
加载:就是把字节码加载到jvm虚拟机中
验证:对字节码文件进行校验是否有错误,比如:操作文件是否是有了try
准备:对类信息等分配内存空间,比如堆,栈中划分内存(参考上面jvm模型)。对静态数据进行默认初始化 比如 int = 0;
解析:就是把符号引用转为直接引用。
看个例子: User user = new User();在未加载时候,user仅仅是一个字符(符号引用)它指向了一个实例。但是这个实例还不存在,准备过程之后,实例分配了内存那么就会有内存地址或者物理地址(直接引用)
初始化:对静态数据初始化。
比如 :static int = 1 ;在准备的时候赋值为0,初始化的时候才赋值为1;
调用构造器。
关于类加载,jvm模型理解,实在是很多很复杂,把复杂的消化并理解华为简单的过程也是学习。