什么是操作栈?
操作数栈也被称为操作栈,它是一个后入先出栈。操作数栈中的每一个元素都是包括long和double在内的任意java类型。32位数据类型所栈的栈容量为1,64位数据类型所占的栈容量为2.
当一个方法刚刚开始执行的时候,这个方法的操作数栈是空的
做算术运算的时候是通过将运算涉及的操作数栈压入顶后调用运算指令来进行的,在调用其他的方法的时候是通过操作数栈来进行方法参数来进行值传递的。
自增自减对JVM来说是怎样操作的
在学习中我们一直被告诫,在Java中任何赋值操作都不是原子操作!并且自增自减也不是原子操作。但究竟是什么原因却不得而知。最近复习了一下Java虚拟机突然想到这个问题打算拿出来仔细研究研究。
分析自增(自减)操作:
- i++(i–):JVM从局部变量表中取出变量i,把变量压入操作栈,然后对局部变量表中的变量i自增一(或自减一)(注意这里是局部变量变中的数据加1,而不是操作栈中的),之后就将操作栈中的数据取出来使用。这样的进行操作之后线程从操作栈中读到的数据就是自增(自减)之前的值;
- ++i(–i):JVM从局部变量表中取出变量i,对局部变量表中的变量i自增一(或自减一),然后把变量压入操作栈,之后就将操作栈中的数据取出来使用。这样的进行操作之后线程从操作栈中读到的数据就是自增(自减)之后的值
之前之所以说 i++ 不是原子操作,即使使用 volatile 修饰也不是线程安全,就是因为,可能 i 被从局部变量表(内存)取出,压入操作栈(寄存器),操作栈中自增,使用栈顶值更新局部变量表(寄存器更新写入内存),其中分为 3 步,volatile 保证可见性,保证每次从局部变量表读取的都是最新的值,但可能这 3 步可能被另一个线程的 3 步打断,产生数据互相覆盖问题,从而导致 i 的值比预期的小。
至于int a = b,这种方式的赋值则也不是原子操作,因为他需要先load b变量的值到栈中,然后在赋值给a。