今天在学习ArrayBlockQueue源码的时候有一个小疑惑 如代码:
/** The queued items */
final Object[] items; //实例变量
/**
* Extracts element at current take position, advances, and signals.
* Call only when holding lock.
*/
private E extract() {
final Object[] items = this.items;
E x = this.<E>cast(items[takeIndex]);
items[takeIndex] = null;
takeIndex = inc(takeIndex);
--count;
notFull.signal();
就是在代码的第9行:
final Object[] items = this.items;
还有很多方法都是这种形式:在方法中要用到某个实例变量的时候采取的方法是先新建一个引用变量来引用原来的对象,而不是直接使用(这里即为this.items)。在网上查看了很多资料最后在iteye的问答区找到了答案
原链接http://www.iteye.com/problems/87918
它举了个例子
final Object[] items = new Object[10];
public void test() {
if(items.length == 0) {
}
int i = items.length;
}
public void test2() {
final Object[] items = this.items;
if(items.length == 0) {
}
int i = items.length;
}
然后javap一下,javap -p -c -s Test >> Test.log,得到如下代码:
public void test();
Signature: ()V
Code:
0: aload_0
1: getfield #3 // Field items:[Ljava/lang/Object;
4: arraylength
5: ifne 8
8: aload_0
9: getfield #3 // Field items:[Ljava/lang/Object;
12: arraylength
13: istore_1
14: return
public void test2();
Signature: ()V
Code:
0: aload_0
1: getfield #3 // Field items:[Ljava/lang/Object;
4: astore_1
5: aload_1 //load 局部变量 items
6: arraylength
7: ifne 10
10: aload_1
// 这里少了getfield,因为aload_1 load的就是items
11: arraylength
12: istore_2
13: return
最终原因:两种写法唯一的区别,是getfield指令,getfield在对象内相对来说开销是比较廉价的,但前者(test方法)显然在代码可读性上,高出很多,如果不存在大量的实例变量引用,性能可以忽略不计,估计这也正是为什么JDK7采用这种简单的写法的原因吧。
重点在于 如果用 this.items 的话 字节码的表现是 aload_0,getfield 如果先复制的话 直接就是 aload_1;估计getfield 的效率比aload_1低所以才会这样使用。
由于我对这些JVM了解的还很少,欢迎各位指教,如果能推介一两本书籍深入了解JVM的话感激不尽!