并发 - Java的AQS.Node源码疑惑
大家讲道理
大家讲道理 2017-04-17 18:00:30
0
2
858

AbstractQueuedSynchronizerNode内部类中,对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类型的变量先赋值给另外一个变量,然后把这个变量返回.
这样设计的目的是什么?

大家讲道理
大家讲道理

光阴似箭催人老,日月如移越少年。

全員に返信(2)
迷茫

リーリー

不要に見えるローカル変数の結果に注目してください。この効果は、ヘルパーが既に初期化されている場合 (つまり、ほとんどの場合)、volatile フィールドへのアクセスは 1 回だけであり (「return helper;」ではなく「return result;」であるため)、これにより、このメソッドの全体的なパフォーマンスは 25% も向上します。[6]

ヘルパー オブジェクトが静的 (クラス ローダーごとに 1 つ) の場合、代替手段は、オンデマンドの初期化ホルダー イディオム [7] です (前に引用したテキストのリスト 16.6[8] を参照してください。)

------ウィキペディア

いいねを押す +0
伊谢尔伦

この方法 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

いいねを押す +0
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート