问题:
类变量:private final E[] items;
private final ReentrantLock lock;
方法:
public void put(E o) throws InterruptedException {
if (o == null) throw new NullPointerException();
final E[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
try {
while (count == items.length)
notFull.await();
} catch (InterruptedException ie) {
notFull.signal(); // propagate to non-interrupted thread
throw ie;
}
insert(o);
} finally {
lock.unlock();
}
}
看黑体字部分 put方法中局部变量items和lock的使用有什么意义?
答案1:
首先在JDK 7中,这段代码变成这样子了:
- final Object[] items;
- public void put(E e) throws InterruptedException {
- checkNotNull(e);
- final ReentrantLock lock = this.lock;
- lock.lockInterruptibly();
- try {
- while (count == items.length)
- notFull.await();
- insert(e);
- } finally {
- lock.unlock();
- }
- }
然后做个实验:
- 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采用这种简单的写法的原因吧。
答案2:
-
之前回答过一篇类似的:但不一样:
http://www.iteye.com/problems/87675
我的理解:
final E[] items = this.items;
final ReentrantLock lock = this.lock;
1、final的数据不可变,因此更安全,防止意外修改,阅读代码时更清晰(我们知道这个东西不能修改,更易于读代码),是一种好的编程习惯;
2、更快,因为你每次都直接this.items会发生如下操作(字节码表示):
4: aload_0 //0 表示当前对象
5: getfield #171; //得到当前对象的items
从字节码可以看出需要两条指令;
如果 final E[] items = this.items; 如果接下来使用的话,直接从堆栈取items的引用,更快。