在很多Java源代码中,(例如LinkedBlockingDeque),我看到了这样的东西;
final ReentrantLock lock = new ReentrantLock();
public void putLast(E e) throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lock();
try {
// do stuff
} finally {
lock.unlock();
}
}我理解基本模式(锁,最终解锁),但我的问题是,为什么在使用它之前对本地作用域的锁变量进行赋值?,为什么要这样做,而不是下面的?
final ReentrantLock lock = new ReentrantLock();
public void putLast(E e) throws InterruptedException {
this.lock.lock();
try {
// do stuff
} finally {
lock.unlock();
}
}它会影响优化吗?第一个例子能防止锁粗化吗?
评论后的编辑:如果你真的不知道为什么会这样,请不要添加答案。这是来自Java源代码,@author标记是Doug,所以我很确定它存在是有原因的。请不要指出代码是完全等价的。
谢谢
发布于 2011-11-05 12:33:08
当您在方法中分配给局部变量时,编译器可以进行一些优化。请参阅在ArrayBlockingQueue中,为什么要将最终成员字段复制到局部变量中?
发布于 2011-11-05 11:30:28
在这段代码中,这并不重要:这两个示例的工作原理完全相同。但是,如果实例变量锁不是最终锁,那么它可能会产生影响,因为实例变量可能在锁定操作期间被更改:然后您希望确保您解锁的锁与您最初锁定的锁相同。
但是,由于锁是最终的,这并不重要:在您的第一个例子中的局部变量分配是多余的。
发布于 2011-11-05 12:49:15
在代码中,我发现了同一作者Doug的两种方法的示例:
LinkedBlockingDeque (自JDK1.6以来)使用“直接访问”方法。CopyOnWriteArrayList (因为JDK1.5)使用“局部变量”方法。java.util.concurrent中的每个成语都有更多的例子,但似乎每个类都选择了一致的风格。
请注意,在所有相关情况下,lock字段已被声明为final。这是最重要的部分,因为最终字段的内存模型语义在JVM (见JLS)中有点特殊。
在此基础上:是否使用本地副本并不会影响多线程正确性。
还请注意,code在更新的代码中选择了较短的样式(如示例所示)。因此,“获取本地副本”成语可能是java.util.concurrent成为JDK的一部分之前以及JVM内存模型被适当采用之前遗留下来的一些东西。我推测,在采用之前的代码可能如下所示:
public void op(){
ReentrantLock lock = getLock();
lock.lock();
try {
realOp();
} finally {
lock.unlock();
}
}其中getLock()确实包含了一些粗糙的多线程安全逻辑。
https://stackoverflow.com/questions/8019831
复制相似问题