1

この質問からReentrantReadWriteLock の「不公平な」モードを理解する方法は? 、どのスレッドが先に来ても、すべてのスレッドがロックを取得する機会は同じだと思います。

だから私はそれをテストするためにこのコードを書きます:

public static void main(String[] args) {
    ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
    final ReadLock readLock = lock.readLock();
    final WriteLock writeLock = lock.writeLock();

    // hold the write lock 3s at first
    new Thread() {
        public void run() {
            writeLock.lock();
            System.out.println(Thread.currentThread().getName() + " got the write lock");
            quietSleep(3);
            writeLock.unlock();
            System.out.println(Thread.currentThread().getName() + " released the write lock");

        };
    }.start();

    // a thread want to get the read lock 1s later
    new Thread() {
        public void run() {
            quietSleep(1);
            readLock.lock();
            System.out.println(Thread.currentThread().getName() + " got the read lock");
        };
    }.start();

    // 1000 threads want to get the write lock 2s later
    for (int i = 0; i < 1000; i++) {
        new Thread() {
            public void run() {
                quietSleep(2);
                writeLock.lock();
                System.out.println(Thread.currentThread().getName() + " got the write lock");
            };
        }.start();
    }
}

private static void quietSleep(int seconds) {
    try {
        Thread.sleep(seconds * 1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

最初に、スレッドが書き込みロックを取得し、それを 3 秒間保持しました。この間、1 つのスレッドが読み取りロックを取得しようとし、次に 1000 のスレッドが書き込みロックを取得しようとします。

ReentrantReadWriteLock はデフォルトで非公平モードを使用するため、書き込みスレッドが書き込みロックを取得する絶好の機会があると思います。しかし、私はそれを何度も実行し、そのたびに読み取りスレッドが勝ちました!

出力は次のとおりです。

Thread-0 got the write lock
Thread-0 released the write lock
Thread-1 got the read lock

「不公平」の理解は間違っていますか?


更新 paxdiabloの回答に従って、コードを次のように変更しました。

new Thread() {
    public void run() {
        quietSleep(1);
        writeLock.lock();
        System.out.println(Thread.currentThread().getName() + " got the write lock");

    };
}.start();

for (int i = 0; i < 1000; i++) {
    new Thread() {
        public void run() {
            quietSleep(2);
            readLock.lock();
            System.out.println(Thread.currentThread().getName() + " got the read lock");
        };
    }.start();
}

現在、書き込みロックを必要とするスレッドがあり、1000 の読み取りスレッドが読み取りロックを必要としています。しかし、出力は次のとおりです。

Thread-0 got the write lock
Thread-0 released the write lock
Thread-1 got the write lock

まだ「先着順」のようです。

4

1 に答える 1

4

不公平であるということは、ロックを順番に渡す必要がないということです (先着順)。それがどのように配布されるかについて、それ以外の保証はしません。実際、必要に応じて、キューに並べて配布することもできます

複数のリーダーが同時にロックを取得できるため、リーダーに配布することを好む可能性がありますが、ライターがロックを取得すると、すべてのリーダーとライターがブロックされます。

ずっと前にリーダー/ライターミューテックスを実装する必要がありましたが、達成する必要があるものに応じて複数のモードがありました。

  • リーダーを優先します。
  • ライターを好む。
  • 代わりのリーダー/ライターを優先します。
  • キューアクセス。

最初の 1 つは、システム実行している可能性があることのようです (スレッド化された性質にもかかわらず、コードが決定論的に実行されている、つまり毎回同じである可能性があるため、「可能性がある」と言います)。


公平と不公平の違いを知りたい場合は、次のことを試してください。

  • 1 つのスレッドに読み取りロックを取得させてから、1 分間スリープ状態にします。
  • そのスリープ中に、スレッドに書き込みロックを要求させ、1 分間スリープ状態にします。
  • 次に、読み取りロックの取得と解放を 10 回試行するループを作成します。

フェアモードでは、RWRRRRRRRRRR. これは、最初の読み取りロック以外のすべてが、書き込みロックが取得されて解放されるまで待機するためです (公平であるため、書き込みが最初に行われます)。

非公平モードではRRRRRRRRRRRW、最初の読み取りロックに干渉しないため、読み取りロックはすべて書き込みロックの前にジャンプすることが許可される場合があります。


もちろん、公平性の概念は著者によって異なる場合があります。読み取りが書き込みの前に忍び寄ることを許可するアルゴリズムのルールの範囲内である可能性がありますが、制限があります。たとえば、書き込みロックが要求されると、書き込みロックの背後でキューに入れられる前に、さらに 5 つの読み取りロックのみがこっそり通過することが許可されます。

誰もそれを実装したとは言いませんが、効率性と公平性のバランスをとることで、実行可能な選択肢になることは間違いありません。

于 2011-11-01T04:37:39.410 に答える