cari

Rumah  >  Soal Jawab  >  teks badan

并发 - Java的AQS.Node源码疑惑

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

大家讲道理大家讲道理2814 hari yang lalu877

membalas semua(2)saya akan balas

  • 迷茫

    迷茫2017-04-17 18:02:30

    // Works with acquire/release semantics for volatile in Java 1.5 and later 
    // Broken under Java 1.4 and earlier semantics for volatile 
    class Foo {
        private volatile Helper helper;
        public Helper getHelper() {
            Helper result = helper;
            if (result == null) {
                synchronized(this) {
                    result = helper;
                    if (result == null) {
                        helper = result = new Helper();
                    }
                }
            }
            return result;
        }
    // other functions and members... }
    

    Perhatikan hasil pembolehubah setempat, yang nampaknya tidak perlu. Kesan daripada ini ialah dalam kes di mana pembantu telah dimulakan (iaitu, kebanyakan masa), medan yang tidak menentu hanya diakses sekali (disebabkan oleh "hasil pulangan;" dan bukannya "pembantu pulang;"), yang boleh meningkatkan prestasi keseluruhan kaedah sebanyak 25 peratus.[6]

    Jika objek pembantu adalah statik (satu setiap pemuat kelas), alternatif ialah pemulaan pada simpulan bahasa pemegang permintaan[7] (Lihat Penyenaraian 16.6[8] daripada teks yang dipetik sebelum ini.)

    -------Wikipedia

    balas
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-17 18:02:30

    Dalam kaedah ini predecessor(), kesan Node p tidak begitu ketara. Tolong izinkan saya menjadikan contoh itu lebih ekstrem:

    final Node extremePredecessor() throws NullPointerException {
        // #L0: Node p = prev;
        // #L1
        if (crazyConditional_1(prev))  {
          ...
        }
        // #L2
        else if (crazyConditional_2(prev))  {
          ...
        }        
        // #L3
        else if (crazyConditional_3(prev)) {
          ...
        }
        // #L4
        else {
          return prev;
        }
    }

    Dengan mengandaikan bahawa 100 rangkaian panggilan akan menukar nilai prev, kemudian antara #L1 dan #L4, sebarang perubahan pada pembolehubah kongsi -- prev akan kelihatan kepada extremePredecessor().
    Ini akan mempunyai masalah berikut:

    • sangat serupa dengan kunci penyegerakan. Kemas kini segerak kepada prev akan menyebabkan kehilangan prestasi sebelum ini menjadi hambatan untuk keseluruhan Baris.

    • Nilai sebelumnya antara #L1 dan #L4 mungkin tidak konsisten kerana urutan lain telah mengubahnya. Ini menjadikannya lebih sukar untuk memahami kod.

    Jika anda menggunakan Node p = prev;, maka selepas #L0, tidak perlu menyegerakkan nilai p. p dari #L1 hingga #L4 juga konsisten.

    Untuk volatile, lihat:
    Kata kunci tidak menentu Spesifikasi Bahasa Java
    https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls- 8.3 .1.4

    balas
    0
  • Batalbalas