類中字段賦值給局部變量後再使用意義何在?
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
Just about every method in all of j.u.c adopts the policy of reading fields as locals whenever a value is used more than once.This way you are sure which value applies when.This is not often pretty, but is easier to visually verify.
The surprising case is doing this even for “final” fields.This is because JVMs are not always smart enough to exploit the fine points of the JMM and not reload read final values, as they would otherwise need to do across the volatile accesses entailed in locking. Some JVMs are smarter than they used to be about this, but still not always smart enough.
文章轉自 並發編程網-ifeve.com
最後更新:2017-05-22 18:01:55