AbstractQueuedSynchronizer
的Node
内部类中,对volatile Node prev
成员变量获取方法predecessor()
如下
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
在源码中,这里对volatile
类型的成员变量prev
的返回,是先把他赋值给一个中间变量p,然后拿p返回。
这种设计在AQS
的源码中很多地方都有涉及到,包括在其它源码中也经常看到对volatile
类型的变量先赋值给另外一个变量,然后把这个变量返回.
这样设计的目的是什么?
迷茫2017-04-17 18:02:30
リーリー
不要に見えるローカル変数の結果に注目してください。この効果は、ヘルパーが既に初期化されている場合 (つまり、ほとんどの場合)、volatile フィールドへのアクセスは 1 回だけであり (「return helper;」ではなく「return result;」であるため)、これにより、このメソッドの全体的なパフォーマンスは 25% も向上します。[6]
ヘルパー オブジェクトが静的 (クラス ローダーごとに 1 つ) の場合、代替手段は、オンデマンドの初期化ホルダー イディオム [7] です (前に引用したテキストのリスト 16.6[8] を参照してください。)
------ウィキペディア
伊谢尔伦2017-04-17 18:02:30
この方法 predecessor()
では、Node p
の効果はそれほど明らかではありません。もう少し極端な例にすることをお許しください:
100 個のスレッド呼び出しによって prev の値が変更されると仮定すると、#L1 と #L4 の間で、共有変数への変更はすべて、extremePredecessor() に表示されます。
これには次の問題があります:
は同期ロックによく似ています。prev
への同期更新はキュー全体のボトルネックになります。
#L1 と #L4 の間の prev の値は、他のスレッドによって変更されたため、矛盾している可能性があります。これにより、コードを理解することがさらに難しくなります。
Node p = prev;
を使用する場合、#L0 の後に p
の値を同期する必要はありません。 #L1 から #L4 までの p
も一致しています。
volatile
については、次を参照してください:
Java 言語仕様の揮発性キーワード
https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls- 8.3 .1.4