この記事では主に Java 言語での cas 命令のロックフリープログラミングの実装例を紹介します。必要な方はそれについて学ぶことができます。
関連コンテンツに初めて触れるときは、volatile キーワードを使用する必要があります。これにより、変数の可視性が保証され、読み取りと書き込みのアトミック操作の実装に使用できることがわかります。 。 。しかし、一部の複合操作を volatile で実装することは無力です。 。 。最も典型的なのはインクリメント演算とデクリメント演算です。 。 。 。
同時環境では、データの一貫性を達成する最も簡単な方法は、同時に 1 つのスレッドだけがデータを操作できるようにロックすることであることがわかっています。 。 。 。たとえば、カウンターは次の方法で実装できます:
public class Counter { private volatile int a = 0; public synchronized int incrAndGet(int number) { this.a += number; return a; } public synchronized int get() { return a; } }
属性 a への同期アクセスを保証するために、すべての操作を synchronized キーワードで変更します。 。 。これにより、確かに同時環境での一貫性を確保できますが、ロック、ロック オーバーヘッド、スレッド スケジューリングなどの使用により、プログラムのスケーラビリティが制限されるため、ロックを使用しない実装が多くあります。 。 。 。
実際、これらのロックフリーのメソッドはすべて、プロセッサによって提供されるいくつかの CAS (比較および切り替え) 命令を使用します。この CAS は具体的に何を行うのでしょうか? 次のメソッドを使用して、CAS によって表されるセマンティクスを説明できます。
public synchronized int compareAndSwap(int expect, int newValue) { int old = this.a; if (old == expect) { this.a = newValue; } return old; }
さて、コードを通して CAS のセマンティクスについてよく理解してください。現在、ほとんどのプロセッサがアトミック CAS 命令を実装しているようです。 。
さて、Java で CAS が使用される場所を見てみましょう。まず、AtomicInteger 型を見てみましょう。これは同時実行ライブラリで提供される型です。これは内部定義であり、使用される属性です。値を保存するため、揮発性型であるため、スレッド間の可視性と読み書きのアトミック性を確保できます。 。 。
private volatile int value;
基本的に、AtomicInteger 型の重要なメソッドはロックフリーの方法で実装されます。 。したがって、同時環境では、このタイプを使用するとパフォーマンスが向上する可能性があります。 。 。
public final int addAndGet(int delta) { for (;;) { int current = get(); int next = current + delta; if (compareAndSet(current, next)) return next; } }
さて、上記のコードはロックフリーのスタックを実装しています。簡単です。 。 。同時環境では、ロックフリーのデータ構造は、ロックよりもはるかに優れた拡張性を実現できます。 。 。
ロックフリー プログラミングについて話すときは、ロックフリー キューについて言及する必要があります。実際、ロックフリー キューの実装は ConcurrentLinkedQueue で提供されています。その重要なメソッドの実装を見てみましょう。
public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); }
さらに、他のメソッドも実際にはロックフリーの方法で実装されています。
最後に、実際のプログラミングでは、これらのロックフリー実装を同時環境で使用する方が良いです。結局のところ、その方がスケーラビリティが優れています。
以上がcas 命令のロックフリー プログラミングを実装する Java の例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。