Java の Atomic パッケージで使用されるコード共有の詳細な紹介

黄舟
リリース: 2017-03-23 10:58:09
オリジナル
1237 人が閲覧しました

はじめに

Java は、JDK1.5 以降 java.util.concurrent.atomic パッケージを提供しています。これにより、プログラマがマルチスレッド環境でロックフリーのアトミック操作を実行できるようになります。アトミック変数の最下層はプロセッサによって提供されるアトミック命令を使用しますが、異なるCPUアーキテクチャは異なるアトミック命令を提供する可能性があり、また何らかの形式の内部ロックも必要とする場合があるため、このメソッドはスレッドがロックされないことを完全に保証することはできません。ブロックされる。

Atomic パッケージの紹介

Atomic パッケージには 12 のクラスと 4 つのアトミック更新メソッド、つまりアトミック更新基本タイプ、アトミック更新配列、アトミック更新参照、およびアトミック更新フィールドがあります。 Atomic パッケージ内のクラスは、基本的に Unsafe を使用して実装されたラッパー クラスです。

アトミック更新基本型クラス

は、基本型をアトミックに更新するために使用されます。 Atomic パッケージは、次の 3 つのクラスを提供します:

  • AtomicBoolean: アトミック更新ブール型

  • AtomicInteger: アトミック更新整数。

  • AtomicLong: アトミック更新ロング。

AtomicInteger の一般的なメソッドは次のとおりです:

  • int addAndGet(int delta): 入力値をインスタンスの値 (AtomicInteger の値) にアトミックに加算し、結果を返します

  • boolean CompareAndSet(int Expect, int update) : 入力値が期待値と等しい場合、値を入力値に原子的に設定します。

  • int getAndIncrement(): 現在の値に原子的に 1 を加算します。 注: ここで返される値は、増分前の値です。

  • void LazySet(int newValue): 最終的には newValue に設定されますが、lazySet を使用して値を設定した後でも、他のスレッドは短期間で古い値を読み取ることができる可能性があります。

  • int getAndSet(int newValue): 値を原子的に newValue に設定し、古い値を返します。

AtomicInteger のサンプル コードは次のとおりです:

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerTest {

	static AtomicInteger ai = new AtomicInteger(1);

	public static void main(String[] args) {
		System.out.println(ai.getAndIncrement());
		System.out.println(ai.get());
	}

}
ログイン後にコピー

Output

1
2
ログイン後にコピー

Dessert

Atomic パッケージは 3 つの基本タイプのアトミック更新を提供しますが、Java の基本タイプには char、float、double などが含まれます。そこで問題は、他の基本型をアトミックに更新するにはどうすればよいでしょうか? Atomic パッケージのクラスは基本的に Unsafe を使用して実装されています。Unsafe のソース コードを見てみましょう。AtomicBoolean のソース コードを見ると、Unsafe には 3 つの CAS メソッドしか提供されていないことがわかります。 Boolean を整数に変換し、compareAndSwapInt を使用して CAS を実行するため、double のアトミック更新も同様のアイデアを使用して実装できます。

配列のアトミック更新クラス

Atomic パッケージには、次の 3 つのクラスが用意されています。

  • AtomicIntegerArray: 整数配列内の要素のアトミック更新。

  • AtomicLongArray: 長整数配列内の要素をアトミックに更新します。

  • AtomicReferenceArray: 参照型配列内の要素をアトミックに更新します。

AtomicIntegerArray クラスは、主に配列内の整数を更新するアトミックな方法を提供します。その一般的なメソッドは次のとおりです

  • int addAndGet(int i, int delta): 入力値をインデックスの要素にアトミックに追加します。配列内の i を加算します。

  • boolean CompareAndSet(int i, int Expect, int update): 現在の値が期待値と等しい場合、配列位置 i の要素を更新値にアトミックに設定します。

サンプルコードは次のとおりです:

public class AtomicIntegerArrayTest {

	static int[] value = new int[] { 1, 2 };

	static AtomicIntegerArray ai = new AtomicIntegerArray(value);

	public static void main(String[] args) {
		ai.getAndSet(0, 3);
		System.out.println(ai.get(0));
                System.out.println(value[0]);
	}

}
ログイン後にコピー

output

3
1
ログイン後にコピー

AtomicIntegerArray クラスそのため、AtomicIntegerArray が内部配列要素を変更する場合、変更が行われても、渡された配列は影響を受けません。 アトミック更新参照型

アトミック更新の基本型である AtomicInteger は、1 つの変数のみを更新できます。複数の変数をアトミックに更新したい場合は、このアトミック更新参照型が提供するクラスを使用する必要があります。 Atomic パッケージは、次の 3 つのクラスを提供します:

    AtomicReference: アトミック更新参照タイプ。
  • AtomicReferenceFieldUpdater: 参照型のフィールドをアトミ​​ックに更新します。
  • AtomicMarkableReference: マーク ビットを使用した参照型のアトミック更新。ブール値のフラグ ビットと参照型をアトミックに更新することができます。構築メソッドは AtomicMarkableReference(VInitialRef, booleanInitialMark) です
  • AtomicReference の使用例コードは次のとおりです:
public class AtomicReferenceTest {

	public static AtomicReference<user> atomicUserRef = new AtomicReference</user><user>();

	public static void main(String[] args) {
		User user = new User("conan", 15);
		atomicUserRef.set(user);
		User updateUser = new User("Shinichi", 17);
		atomicUserRef.compareAndSet(user, updateUser);
		System.out.println(atomicUserRef.get().getName());
		System.out.println(atomicUserRef.get().getOld());
	}

	static class User {
		private String name;
		private int old;

		public User(String name, int old) {
			this.name = name;
			this.old = old;
		}

		public String getName() {
			return name;
		}

		public int getOld() {
			return old;
		}
	}
}
ログイン後にコピー

Output

Shinichi
17
ログイン後にコピー

Atomic update field class

特定のクラスの特定のフィールドのみが必要な場合は、アトミック更新フィールド クラスを使用する必要があります。Atomic パッケージには次の 3 つのクラスが用意されています:

    AtomicIntegerFieldUpdater: 整数フィールドをアトミ​​ックに更新するためのアップデーター。
  • AtomicLongFieldUpdater: 長整数フィールドをアトミ​​ックに更新するためのアップデーター。
  • AtomicStampedReference:原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于原子的更数据和数据的版本号,可以解决使用CAS进行原子更新时,可能出现的ABA问题。

原子更新字段类都是抽象类,每次使用都时候必须使用静态方法newUpdater创建一个更新器。原子更新类的字段的必须使用public Volatile修饰符。AtomicIntegerFieldUpdater的例子代码如下:

public class AtomicIntegerFieldUpdaterTest {

	private static AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater
			.newUpdater(User.class, "old");

	public static void main(String[] args) {
		User conan = new User("conan", 10);
		System.out.println(a.getAndIncrement(conan));
		System.out.println(a.get(conan));
	}

	public static class User {
		private String name;
		public volatile int old;

		public User(String name, int old) {
			this.name = name;
			this.old = old;
		}

		public String getName() {
			return name;
		}

		public int getOld() {
			return old;
		}
	}
}
ログイン後にコピー

输出

10
11
ログイン後にコピー

以上がJava の Atomic パッケージで使用されるコード共有の詳細な紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート