我们正在与同事讨论PriorityBlockingQueue
(Oracle JDK 8,v1.8.0_131)代码中的以下惯用法。在几乎每次使用字段private final ReentrantLock lock
时,开发人员都选择先将其存储在本地变量中(也定义为final
)。模式如下:
...
private final ReentrantLock lock; // initialized as 'new ReentrantLock()' in constructors
...
public E poll() {
final ReentrantLock lock = this.lock; // <--
lock.lock();
这种选择很难解释,我们没有人能看到这种优势,而不是直接使用该字段。由于原始字段为final
,因此在多线程上下文中不需要这样做以防止或减少脏读的风险。由于该字段不是volatile
,因此这不是只访问一次易失字段的优化。这可能是一个非常微小的微优化,其中字段引用驻留在堆中,而局部变量驻留在堆栈中,并且从堆栈读取的效率更高(或可能更高?)。但是我们在这里谈论的最多是皮秒。而且这个习语不用于其他字段访问-仅以这种方式管理锁...
因此我们被困在“ 这没用,可以(应该)重写为直接字段访问”。但是我对我们的结论有些困惑。我肯定知道JDK中的大多数代码都非常聪明,并且成功地通过了一些高级工程师的代码审查。我们在这里错过了一些棘手的实现细节吗?