8(原子タイプ)を学習マルチスレッドプログラミング。

簡単な紹介

JavaはJDK 1.5には、java.util.concurrent.atomicパッケージを提供し、このパッケージの原子操作クラスは、変数、スレッドセーフな方法を更新し、シンプルで効率的なパフォーマンスの使用が提供されます。主にそれは、アトミック更新基本的なタイプ、アトミック更新アレイであり、基準原子原子更新プロパティを更新し、アトミック更新モードの四種類を提供します。

原子クラスは、基本的には、スレッドの安全性を確保するために、安全でないを使用しています。

public final class Unsafe {
    ...

    public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);

    public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

    public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

    ...
}

JDK 1.8で、ダグ・リーは、より効率的なロックフリーソリューションを提供し、パッケージのような平行アキュムレータ原子LongAccumulatorで加えました。

アトミック更新基本データ型

  • AtomicBoolean:アトミック更新ブール
  • AtomicInteger:整数原子更新
  • AtomicLong:ロングアトミック更新
public class AtomicIntegerTest {

    private static CountDownLatch countDownLatch = new CountDownLatch(1);

    private static AtomicInteger atomicInteger = new AtomicInteger(1);

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                try {
                    countDownLatch.await();
                    // 以原子方式将当前值加 1,并返回之前的值
                    System.out.print(atomicInteger.getAndIncrement() + " ");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            thread.start();
        }
        // 线程同时进行争抢操作
        countDownLatch.countDown();
        Thread.sleep(2000);
        System.out.println();
        // 以原子方式将输入的数值与实例中的值相加,并返回结果。
        System.out.println(atomicInteger.addAndGet(10));
        // CAS 操作
        atomicInteger.compareAndSet(21, 30);
        System.out.println(atomicInteger.get());
    }
}

アトミック更新の配列

  • AtomicIntegerArray:元素の原子更新整数配列
  • AtomicLongArray:元素の原子更新長い整数配列
  • AtomicReferenceArray:元素の原子更新参照型アレイ
public class AtomicReferenceArrayTest {

    // AtomicReferenceArray 会将当前数组(VALUE)复制一份,所以当 AtomicReferenceArray 对内部的数组元素进行修改时,不会影响传入的数组。
    private static Stu[] VALUE = new Stu[]{new Stu(System.currentTimeMillis(), "张三"),new Stu(System.currentTimeMillis(), "李四")};

    private static AtomicReferenceArray<Stu> REFERENCE_ARRAY = new AtomicReferenceArray<>(VALUE);

    public static void main(String[] args) {
        // 修改指定位置元素的值
        REFERENCE_ARRAY.getAndSet(0, new Stu(System.currentTimeMillis(), "王五"));
        System.out.println(REFERENCE_ARRAY.get(0));
        System.out.println(VALUE[0]);
    }
}

原子更新引用

  • AtomicReference:アトミック更新基準タイプ
  • AtomicMarkableReference:参照型原子マーク位置を更新
  • AtomicStampedReference:参照型のアトミック更新のバージョン番号
public class AtomicStampedReferenceTest {

    private static Stu stu = new Stu(System.currentTimeMillis(), "张三");
    /**
     * 更新对象的时候带一个版本号,可以防止 CAS 中 ABA 问题。原理在于 compare 的时候不仅比较原来的值,还比较版本号。同理更新的时候也需要更新版本号
     */
    private static AtomicStampedReference<Stu> stampedReference = new AtomicStampedReference(stu, 1);

    public static void main(String[] args) {
        System.out.println(stampedReference.getReference());
        Stu newStu = new Stu(System.currentTimeMillis(), "李四");
        int stamp = stampedReference.getStamp();
        stampedReference.compareAndSet(stu, newStu, stamp, stamp++);
        System.out.println(stampedReference.getReference());
    }
}

アトミック更新特性

  • AtomicIntegerFieldUpdater:整数アトミック更新フィールドアップデータ
  • AtomicLongFieldUpdater:長い整数フィールドアップデータの原子更新
  • AtomicReferenceFieldUpdater:フィールドの原子更新参照型
public class AtomicReferenceFieldUpdaterTest {

    // 创建原子更新器,并设置需要更新的对象类和对象的属性
    private static AtomicReferenceFieldUpdater<Stu, String> atomicUserFieldRef = AtomicReferenceFieldUpdater.newUpdater(Stu.class, String.class, "name");

    public static void main(String[] args) {
        Stu stu = new Stu(System.currentTimeMillis(), "张三");
        atomicUserFieldRef.set(stu, "李四");
        System.out.println(stu.getName());
    }
}

更新のクラス属性がパブリックvolatile修飾子を使用しなければならないことに留意すべきです。次は、ソースコンテンツAtomicReferenceFieldUpdater、次のとおりです。

            if (vclass.isPrimitive())
                throw new IllegalArgumentException("Must be reference type");

            if (!Modifier.isVolatile(modifiers))
                throw new IllegalArgumentException("Must be volatile type");

1.8平行アキュムレータ

AtomicLongは、CASによって、非ブロッキングアトミック操作を提供するために、変数の値を維持します。それよりも少なく、CASは高いN同時マルチスレッドで、CPUリソースの巨大な浪費である無限ループスピンロックを維持する必要性、の試みに失敗しました。

もしそうであれば、スレッドの数が同じでより多くのリソースのために競争するように、複数の変数への変数は、その後、パフォーマンスの問題が解決されませんか?はい、JDK8はLongAdderはこのアイデアが設けられています。

LongAdderコアアイデアをセグメントは、Striped64、Striped64長い基部と二つのパラメータを継承細胞[]細胞、ルックLongAddrコアコードが続きます。

public void add(long x) {
        Cell[] as; long b, v; int m; Cell a;
        //想要add一个元素的时候,先看一下 cells 数组是否为空,如果是空的就尝试去看能不能直接加到 base上面,如果线程竞争很小就加到 base上面了,函数结束
        //如果 cells 是空的,并且竞争很大,cas 失败,就进入if块内,创建 cells
        //如果不是空的就进入到 cell 数组中看能加到哪个上面去
        if ((as = cells) != null || !casBase(b = base, b + x)) {
            boolean uncontended = true;
            //如果 cells 是空的,就执行增加操作
            if (as == null || (m = as.length - 1) < 0 || (a = as[getProbe() & m]) == null || !(uncontended = a.cas(v = a.value, v + x)))
                longAccumulate(x, null, uncontended);
        }
    }

だから、あなただけの和()メソッド、つまりベース+セル[]配列の要素とをLongAdder呼び出し、蓄積された結果を取得したいです。合計の計算がマージされない場合が同時更新が発生したことに留意すべきです。

おすすめ

転載: www.cnblogs.com/jmcui/p/11481773.html