ホームページ  >  記事  >  Java  >  Java 同時プログラミングで StampedLock ロックを使用する方法

Java 同時プログラミングで StampedLock ロックを使用する方法

WBOY
WBOY転載
2023-04-24 08:01:061328ブラウズ

StampedLock:

StampedLock は、コンカレント パッケージの JDK8 バージョンに追加された新しいロックです。このロックは、読み取りおよび書き込み制御の 3 つのモードを提供します。呼び出し ロックを取得する一連の関数が長い変数を返すとき、それをスタンプと呼び、このスタンプはロックの状態を表します。ロックを取得する try 一連の関数は、ロックの取得が失敗した場合にスタンプ値 0 を返します。ロックの解放およびロックの変換のメソッドを呼び出すときは、ロックの取得時に返されたスタンプ値を渡す必要があります。

StampedLock によって提供される 3 つの読み取りおよび書き込みモード ロックは次のとおりです。

  • 書き込みロック witeLock: は、行 ロックまたは排他的ロックを行います。一度に 1 つのスレッドのみがロックを取得できます。スレッドがロックを取得すると、読み取りロックと書き込みロックを要求している他のスレッドは待機する必要があります。これは ReentrantReadWriteLock の書き込みロックに似ています (違いは、ここでの書き込みロック。ロックは非リエントラント ロックです): ロックは、現在読み取りロックまたは書き込みロックを保持しているスレッドがない場合にのみ取得できます。ロックのリクエストが成功すると、ロックのバージョンを表すスタンプ変数が返されます。ロックが解放されるときは、unlockWrite メソッドを呼び出して、ロック日付のスタンプ パラメータを渡す必要があります。また、ノンブロッキングの tryWriteLock メソッドを提供します。

  • 悲観的読み取りロック readLock: は共有ロックです。排他的書き込みロックを取得するスレッドがない場合、複数のスレッドが同時にロックを取得できます。スレッドがすでに書き込みロックを保持している場合、他のスレッドによる読み取りロックの取得要求はブロックされます。これは ReentrantReadWriteLock の読み取りロックと似ています (ここでの読み取りロックは非リエントラント ロックである点が異なります)。ここで言う悲観とは、データを具体的に操作する前に、操作するデータが他のスレッドによって変更される可能性があると悲観的に判断するため、最初にデータをロックする必要があることを意味します。これは、読み取りを減らし、書き込みを増やす場合の考慮事項です。ロックのリクエストが成功すると、ロックのバージョンを表すスタンプ変数が返されます。ロックが解放されるときは、unlockRead メソッドを呼び出してスタンプ パラメータを渡す必要があります。また、ノンブロッキングの tryReadLock メソッドを提供します。

  • 楽観的読み取りロック tryOptimisticRead: 悲観的ロックに関連しており、ロック ステータスはデータを操作する前に CAS を通じて設定されず、ビット操作のみが使用されます。テスト。現在書き込みロックを保持しているスレッドがない場合は、ゼロ以外のスタンプ バージョン情報が単純に返されます。スタンプを取得した後、データを具体的に操作する前に、validate メソッドを呼び出してスタンプが使用できなくなっているかどうか、つまり、tryOptimisticRead がスタンプを返してから現在のスレッドまでの間に書き込みロックを保持している他のスレッドがあるかどうかを確認する必要があります。そうであれば、validate は 0 を返しますが、そうでない場合は、ロックのスタンプ バージョンを使用してデータを操作できます。 tryOptimisticRead はロック ステータスの設定に CAS を使用しないため、明示的にロックを解放する必要はありません。このロックの特徴の 1 つは、読み取りが多く書き込みが少ないシナリオに適していることです。読み取りロックの取得には検証のためのビット操作のみが使用され、CAS 操作が含まれないため、効率が大幅に高くなります。同時に、実際のロックを使用しないため、データの一貫性が確保されます。操作する変数をメソッドスタックにコピーする必要があり、データを操作する際に、他の書き込みスレッドによってデータが変更されている可能性があります。メソッド スタック内のデータはスナップショットであるため、最も返されるデータは最新のデータではありませんが、一貫性は保証されています。

StampedLock は、特定の条件下でこれら 3 つのロックの相互変換もサポートしています。たとえば、long tryConvertToWriteLock(long stamp) は、スタンプでマークされたロックを書き込みロックにアップグレードすることを期待します。

この関数は、次の状況で有効なスタンプを返します (つまり、書き込みロックの昇格が成功しました):

  • #現在のロックはすでに書き込みロック モードになっています。

  • 前のロックは読み取りロック モードであり、他のスレッドは読み取りロック モードではありません

  • 現在オプティミスティック読み取りモードです。現在の書き込みロックは利用可能です

さらに、StampedLock の読み取りロックと書き込みロックは非再入ロックであるため、取得する操作を呼び出さないでください。ロックを取得した後、ロックを解放する前のロック。呼び出し元のスレッドがブロックされるのを避けるため。複数のスレッドが同時に読み取りロックと書き込みロックを取得しようとした場合、誰が最初にロックを取得するかについて一定の規則はなく、完全にベストエフォート方式でランダムに行われます。また、ロックは Lock または ReadWriteLock インターフェイスを直接実装するのではなく、双方向のブロッキング キューを内部的に維持します。

以下は、上で紹介した概念を理解するために、JDK8 で提供される 2 次元点を管理する例です。

package LockSupportTest;

import com.sun.org.apache.bcel.internal.generic.BREAKPOINT;

import java.util.concurrent.locks.StampedLock;

public class Point_Class {
    private double x,y;
    private final StampedLock sl = new StampedLock();
    
    void move(double deltaX, double deltaY) {
        long stamp = sl.writeLock();
        try {
            x += deltaX;
            y += deltaY;
        } finally {
            sl.unlockWrite(stamp);
        }
    }
    
    double distanceFromOrin() {
        long stamp = sl.tryOptimisticRead();
        double currentX = x, currentY = y;
        if (!sl.validate(stamp)) {
            stamp = sl.readLock();
            try {
                currentX = x;
                currentY = y;
            } finally {
                sl.unlockRead(stamp);
            }
        }
        return Math.sqrt(currentX*currentX + currentY*currentY);
    }
    
    void moveIfAtOrigin(double newX, double newY) {
        long stamp = sl.readLock();
        try {
            while (x == 0.0 && y == 0.0) {
                long ws = sl.tryConvertToWriteLock(stamp);
                if (ws != 0L) {
                    stamp = ws;
                    x = newX;
                    y = newY;
                    break;
                } else {
                    sl.unlockRead(stamp);
                    stamp = sl.writeLock();
                }
            }
        } finally {
                    sl.unlock(stamp);
                }
            }
}

上記のコードでは、Point クラスには、点の 2 次元座標を表すために使用される 2 つのメンバー変数 (x、y) と、座標変数を操作するための 3 つのメソッドがあります。さらに、StampedLock オブジェクトがインスタンス化され、操作のアトミック性が保証されます。

以上がJava 同時プログラミングで StampedLock ロックを使用する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。