2011-11-11 56 views
3

在瀏覽java.util.concurrency包的源代碼時,我注意到了我以前從未見過的ReentrantLock的慣用用法:成員RentrantLock變量從未從內部直接訪問一個方法 - 它們總是由局部變量引用引用。在併發包中使用ReentrantLock

樣式#1 e.g從java.util.concurrent.ThreadPoolExecutor中

private final ReentrantLock mainLock = new ReentrantLock(); 
... 
// why a local reference to final mainlock instead of directly using it? 
final ReentrantLock mainLock = this.mainLock; 
mainLock.lock(); 
try { 
...  
} finally { 
    mainLock.unlock(); 
} 

然而,在其它地方的最後成員變量直接使用,無需首先獲得本地參考。

樣式#2例如從Java併發實踐

private final Lock lock = new ReentrantLock(); 
... 
// here the final lock is used directly 
lock.lock(); 
try { 
... 
} finally { 
lock.unlock(); 
} 

我想知道是什麼用風格#1風格#2的好處是什麼?

感謝

更新

感謝所有的反應,尤其是本Manes認爲對於第一識別性能。 因此我能夠與評論「cache finals across volatiles

  • 根據道格發現在2003以下的附加細節

    1. Doug Lea的介紹這個成語,它是「for performance-critical code like that inside j.u.c.」,雖然「這不是一個推薦做法」,他‘does not discourage it either
    2. 布賴恩戈茨(JCIP的作者)也同意,除非它是性能關鍵型應用程序‘don't worry
  • +0

    據我所知沒有。這是一個「最終」成員,所以沒有必要抓住當地的參考。這可能表明兩個不同的程序員在這些代碼段上工作 - 僅此而已。 – Gray

    +0

    我看不出有一個理由去接受一個局部變量,除非代碼的以前版本把'mainLock'定義爲非最終的。 – Bringer128

    +2

    查看此[線程](http://old.nabble.com/Making-copy-of-a-reference-to-ReentrantLock-tt30730392.html#a30733348)以瞭解有關此字節碼優化技巧的詳細信息。 –

    回答

    2

    本Manes的鏈接ŧ在討論JIT優化的評論中,discussion。顯然,熱點編譯器不會優化final字段的負載,因爲它可以通過反射或Unsafe類進行修改。

    因此,該機制提供了一個小的速度改進,允許JIT優化鎖實例的加載。他們沒有詳細說明哪些優化會發生,但我懷疑優化是爲了防止從主內存重新加載實例。這將允許線程多次使用重入鎖而不會受到懲罰。

    不幸的是,這個答案是基於郵件列表討論的猜測。如果有人能糾正我,請繼續!

    +0

    是的,看到這個[博客文章](http://www.azulsystems.com/blog/cliff/2011-10-27-final-fields-part-2)的更多見解。 –