Rumah  >  Artikel  >  Java  >  Apakah status pelaksanaan LongAdder dalam pengaturcaraan serentak Java?

Apakah status pelaksanaan LongAdder dalam pengaturcaraan serentak Java?

WBOY
WBOYke hadapan
2023-05-09 12:52:15722semak imbas

kaedah LongAccumulate

final void longAccumulate(long x, LongBinaryOperator fn,
                          boolean wasUncontended) {
    int h;
    if ((h = getProbe()) == 0) {
        ThreadLocalRandom.current(); // force initialization
        h = getProbe();
        wasUncontended = true;
    }
    boolean collide = false;                // True if last slot nonempty
    for (;;) {
        Cell[] as; Cell a; int n; long v;
        if ((as = cells) != null && (n = as.length) > 0) {
            if ((a = as[(n - 1) & h]) == null) {
                if (cellsBusy == 0) {       // Try to attach new Cell
                    Cell r = new Cell(x);   // Optimistically create
                    if (cellsBusy == 0 && casCellsBusy()) {
                        boolean created = false;
                        try {               // Recheck under lock
                            Cell[] rs; int m, j;
                            if ((rs = cells) != null &&
                                (m = rs.length) > 0 &&
                                rs[j = (m - 1) & h] == null) {
                                rs[j] = r;
                                created = true;
                            }
                        } finally {
                            cellsBusy = 0;
                        }
                        if (created)
                            break;
                        continue;           // Slot is now non-empty
                    }
                }
                collide = false;
            }
            else if (!wasUncontended)       // CAS already known to fail
                wasUncontended = true;      // Continue after rehash
            else if (a.cas(v = a.value, ((fn == null) ? v + x :
                                         fn.applyAsLong(v, x))))
                break;
            else if (n >= NCPU || cells != as)
                collide = false;            // At max size or stale
            else if (!collide)
                collide = true;
            else if (cellsBusy == 0 && casCellsBusy()) {
                try {
                    if (cells == as) {      // Expand table unless stale
                        Cell[] rs = new Cell[n << 1];
                        for (int i = 0; i < n; ++i)
                            rs[i] = as[i];
                        cells = rs;
                    }
                } finally {
                    cellsBusy = 0;
                }
                collide = false;
                continue;                   // Retry with expanded table
            }
            h = advanceProbe(h);
        }
        else if (cellsBusy == 0 && cells == as && casCellsBusy()) {
            boolean init = false;
            try {                           // Initialize table
                if (cells == as) {
                    Cell[] rs = new Cell[2];
                    rs[h & 1] = new Cell(x);
                    cells = rs;
                    init = true;
                }
            } finally {
                cellsBusy = 0;
            }
            if (init)
                break;
        }
        else if (casBase(v = base, ((fn == null) ? v + x :
                                    fn.applyAsLong(v, x))))
            break;                          // Fall back on using base
    }
}

Kod itu panjang, mari analisa dalam bahagian, mula-mula perkenalkan kandungan setiap bahagian

  • Bahagian satu: forSebelum gelung Kod ini terutamanya untuk mendapatkan nilai cincang benang Jika ia adalah 0, ia akan dipaksa untuk memulakan

  • Bahagian 2: forPernyataan if pertama dalam. gelung, dalam Cell Pengumpulan dan pengembangan dalam tatasusunan

  • Bahagian 3: forPernyataan else if pertama dalam gelung, fungsi bahagian ini adalah untuk mencipta Tatasusunan Cell dan mulakan

  • Bahagian 4: Penyataan for kedua dalam gelung else if, apabila persaingan tatasusunan Cell sengit, cuba kumpulkan pada base

Nilai cincang benang

int h; 
if ((h = getProbe()) == 0) { 
    ThreadLocalRandom.current(); // force initialization 
    h = getProbe(); 
    wasUncontended = true;   // true表示没有竞争
} 
boolean collide = false; // True if last slot nonempty 可以理解为是否需要扩容

Kod teras bahagian ini ialah kaedah getProbe Fungsi kaedah ini adalah untuk mendapatkan nilai hash daripada benang, yang sesuai untuk kedudukan kemudian ke dalam tatasusunan Cell melalui operasi bit Pada kedudukan tertentu, jika ia 0, pemulaan paksa akan dilakukan

Memulakan tatasusunan Sel

.
final void longAccumulate(long x, LongBinaryOperator fn,
                          boolean wasUncontended) {
    // 省略...
    for (;;) {
        Cell[] as; Cell a; int n; long v;
        if ((as = cells) != null && (n = as.length) > 0) {
            // 省略...
        }
        else if (cellsBusy == 0 && cells == as && casCellsBusy()) {  // 获取锁
            boolean init = false;  // 初始化标志
            try {                           // Initialize table
                if (cells == as) {
                    Cell[] rs = new Cell[2];  // 创建Cell数组
                    rs[h & 1] = new Cell(x);  // 索引1位置创建Cell元素,值为x=1
                    cells = rs;   // cells指向新数组
                    init = true;  // 初始化完成
                }
            } finally {
                cellsBusy = 0;  // 释放锁
            }
            if (init)
                break;  // 跳出循环
        }
        else if (casBase(v = base, ((fn == null) ? v + x :
                                    fn.applyAsLong(v, x))))
            break;                          // Fall back on using base
    }
}

Dalam kes pertama, tatasusunan Cell ialah null, jadi ia akan memasuki pernyataan else if pertama, dan tiada urutan lain untuk beroperasi, jadi cellsBusy==0, cells==as juga true dan casCellsBusy() cuba melakukan operasi cellsBusy pada cas dan menukarnya kepada 1, yang juga true.

mula-mula mencipta tatasusunan Cell dengan dua elemen, dan kemudian menetapkan h & 1 kepada 1's value pada kedudukan indeks 1 melalui operasi bit benang Cell , Kemudian tetapkan semula kepada cells, tandakan permulaan berjaya, ubah suai cellsBusy kepada 0 untuk menunjukkan melepaskan kunci, dan akhirnya lompat keluar dari gelung, operasi pemulaan selesai.

Kumpul asas

final void longAccumulate(long x, LongBinaryOperator fn,
                          boolean wasUncontended) {
    // 省略...
    for (;;) {
        Cell[] as; Cell a; int n; long v;
        if ((as = cells) != null && (n = as.length) > 0) {
            // 省略...
        }
        else if (cellsBusy == 0 && cells == as && casCellsBusy()) {
            // 省略...
        }
        else if (casBase(v = base, ((fn == null) ? v + x :
                                    fn.applyAsLong(v, x))))
            break;                          // Fall back on using base
    }
}

Pernyataan else if kedua bermaksud apabila persaingan untuk semua kedudukan dalam tatasusunan Cell sengit, cuba kumpulkan pada base , boleh difahami sebagai jaminan akhir

Selepas susunan Sel dimulakan

final void longAccumulate(long x, LongBinaryOperator fn,
                          boolean wasUncontended) {
    // 省略...
    for (;;) {
        Cell[] as; Cell a; int n; long v;
        if ((as = cells) != null && (n = as.length) > 0) {  // as初始化之后满足条件
            if ((a = as[(n - 1) & h]) == null) {  // as中某个位置的值为null
                if (cellsBusy == 0) {       // Try to attach new Cell 是否加锁
                    Cell r = new Cell(x);   // Optimistically create 创建新Cell
                    if (cellsBusy == 0 && casCellsBusy()) { // 双重检查是否有锁,并尝试加锁
                        boolean created = false;  // 
                        try {               // Recheck under lock
                            Cell[] rs; int m, j;
                            if ((rs = cells) != null &&
                                (m = rs.length) > 0 &&
                                rs[j = (m - 1) & h] == null) {  // 重新检查该位置是否为null
                                rs[j] = r;  // 该位置添加Cell元素
                                created = true;  // 新Cell创建成功
                            }
                        } finally {
                            cellsBusy = 0;  // 释放锁
                        }
                        if (created)
                            break;  // 创建成功,跳出循环
                        continue;           // Slot is now non-empty
                    }
                }
                collide = false;  // 扩容标志
            }
            else if (!wasUncontended)       // 上面定位到的索引位置的值不为null
                wasUncontended = true;      // 重新计算hash,重新定位其他索引位置重试
            else if (a.cas(v = a.value, ((fn == null) ? v + x :
                                         fn.applyAsLong(v, x))))  // 尝试在该索引位置进行累加
                break;
            else if (n >= NCPU || cells != as)  // 如果数组长度大于等于CPU核心数,就不能在扩容
                collide = false;            // At max size or stale
            else if (!collide)  // 数组长度没有达到最大值,修改扩容标志可以扩容
                collide = true;
            else if (cellsBusy == 0 && casCellsBusy()) { // 尝试加锁
                try {
                    if (cells == as) {      // Expand table unless stale
                        Cell[] rs = new Cell[n << 1];  // 创建一个原来长度2倍的数组
                        for (int i = 0; i < n; ++i)
                            rs[i] = as[i];  // 把原来的元素拷贝到新数组中
                        cells = rs;  // cells指向新数组
                    }
                } finally {
                    cellsBusy = 0;  // 释放锁
                }
                collide = false;  // 已经扩容完成,修改标志不用再扩容
                continue;                   // Retry with expanded table
            }
            h = advanceProbe(h);  // 重新获取hash值
        }
        // 省略...
}

Analisis logik keseluruhan mengikut komen dalam kod

  • Pertama sekali, jika anda cari tatasusunan Nilai pada kedudukan ini ialah null, menunjukkan bahawa operasi boleh dilakukan pada kedudukan ini Cipta Cell baharu dan mulakan nilai kepada 1 dan letakkan pada kedudukan ini, kira semula hash nilai dan cuba lagi

  • Kedudukan yang diposisikan sudah mempunyai nilai, menunjukkan bahawa terdapat persaingan antara urutan wasUncontended false dan kira semula trueCuba semulahash

  • Kedudukan yang diposisikan mempunyai nilai dan

    sudah wasUncontended, cuba kumpulkan pada kedudukan itutrue

  • Apabila pengumpulan gagal, ia dinilai sama ada kapasiti tatasusunan telah mencapai maksimum Jika ya, pengembangan tidak boleh dilakukan Anda hanya boleh

    dan cuba lagi rehash

  • Jika tiada syarat sebelum ini dipenuhi dan bendera pengembangan ialah

    Jika ia ditandakan sebagai collide, tukarkannya kepada false, menunjukkan bahawa kapasiti boleh dikembangkan, dan kemudian true cuba semula rehash

  • Mula-mula cuba kunci, dan jika ia berjaya, operasi pengembangan akan dilakukan Panjang pengembangan pertama ialah

    kali ganda daripada yang sebelumnya, dan kemudian tatasusunan asal kandungan disalin ke tatasusunan baharu, dan pengembangan selesai. 2

Atas ialah kandungan terperinci Apakah status pelaksanaan LongAdder dalam pengaturcaraan serentak Java?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam