ArrayBlockingQueue源码中为什么方法要用局部变量引用类变量
2016-05-30 14:42
447 查看
问题:
类变量:
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中,这段代码变成这样子了:
Java代码
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();
}
}
然后做个实验:
Java代码
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,得到如下代码:
Java代码
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的引用,更快。
原文地址: http://www.iteye.com/problems/87918
类变量:
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中,这段代码变成这样子了:
Java代码
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();
}
}
然后做个实验:
Java代码
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,得到如下代码:
Java代码
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的引用,更快。
原文地址: http://www.iteye.com/problems/87918
相关文章推荐
- IBM MQQueueManager 直接连接
- Java中String、StringBuffer、StringBuilder的区别及面试经常出现的问题
- 存储过程 返回值 procedure return values
- Java中String、StringBuffer、StringBuilder的区别及面试经常出现的问题
- PKIX path building failed 的问题
- ueditor 跨域上传问题
- DECLARE_WAITQUEUE(wait, current)的分析
- UI进阶 SQLite错误码
- UIDatePicker 轮转日期选择器 时间选择器
- 解决UIScrollView和滑动返回手势的冲突
- Android高级UI GestureDetector监听各种手势
- ValidateRequest="false"
- iOS的QuickTime Plugin
- UITableViewCell上的按钮点击事件处理
- ERROR: Remote error: BdbQuit 的解决办法
- 【iOS开发】自定义UIView边框的颜色
- View生命周期
- [leetcode] 128. Longest Consecutive Sequence
- request.getParameter(“参数名”) 中文乱码解决方法
- iOS开发中UIWindow