類中欄位賦值給區域性變數後再使用意義何在?
阿新 • • 發佈:2018-12-23
Concurrency-interest郵件列表中有人問了這麼一個問題:ArrayBlockingQueue中有個物件欄位lock,在ArrayBlockingQueue的很多方法中,使用這個lock時都將其先賦值給一個區域性變數,然後再通過區域性變數呼叫lock上的方法,而沒有直接使用lock欄位,如remainingCapacity方法中先將this.lock賦值給一個區域性變數lock,然後再使用這個區域性變數:
public class ArrayBlockingQueue { private final ReentrantLock lock; //...other fields and methods public int remainingCapacity() { final ReentrantLock lock = this.lock; lock.lock(); try { return items.length - count; } finally { lock.unlock(); } } }
而不是像這樣直接使用類中的欄位:
public class ArrayBlockingQueue { private final ReentrantLock lock; //...other fields and methods public int remainingCapacity() { this.lock.lock(); try { return items.length - count; } finally { this.lock.unlock(); } } }
那麼為什麼要這麼做,有什麼理由或說法?
Doug Lea
歸根究底是由於記憶體模型與OOP之間的原則不一致。
幾乎j.u.c包中的每個方法都採用了這樣一種策略:當一個值會被多次使用時,就將這個欄位讀出來賦值給區域性變數。雖然這種做法不雅觀,但檢查起來會更直觀。
final欄位也會做這樣處理,可能有些令人不解。這是因為JVM並不足夠智慧,不能充分利用JMM已經提供了安全保證的可優化點,比如可以不用重新載入final值到快取。相比過去,JVM在這方面有很大進步,但仍不夠智慧。
原文如下:
It’s ultimately due to the fundamental mismatch between memory models
and OOP