2

これはリーダー/ライターの実装です。つまり、多くのリーダーは読み取ることができますが、一度に書き込むことができるライターは 1 つだけです。これは期待どおりに機能しますか?

public class ReadersWriters extends Thread{

static int num_readers = 0;
static int writing = 0;

public void read_start() throws InterruptedException {         

    synchronized(this.getClass()) {
        while(writing == 1) wait();
        num_readers++;
    }        
}

public void read_end() {
    synchronized(this.getClass()) {
        if(--num_readers == 0) notifyAll();
    }
}

public void write_start() throws InterruptedException{

    synchronized(this.getClass()) {
        while(num_readers > 0) wait();
        writing = 1;
    } 
}

public void write_end() {
    this.getClass().notifyAll();
}
}

また、この実装は各メソッドの宣言とは異なりますか

public static synchronized read_start() 

例えば?

ありがとう

4

4 に答える 4

6

this.wait()いいえ -で同期していないにもかかわらず、暗黙的に を呼び出していますthisが、代わりにクラスで呼び出しています。同様に、あなたは を呼び出しthis.notifyAll()ていread_endます。私の提案:

  • 拡張しないでくださいThread-スレッドをまったく専門化していません。
  • インスタンス メンバーからこのような静的変数を使用しないでください。オブジェクトごとに状態があるように見えますが、実際にはありません個人的には、インスタンス変数を使用するだけです。
  • 名前にアンダースコアを使用しないでください。従来の Java 名はnumReaders, readEnd(またはそれ以上endRead) などです。
  • this可能であれば、どちらかまたはクラスで同期しないでください。個人的には、private final Object変数をロックする (および待機するなど) ことを好みます。そうすれば、自分のコードだけが同期できることがわかり、推論が容易になります。
  • 0 に設定writingすることはありません。そもそも a の代わりに整数を使用する理由はありbooleanますか?

もちろん、可能であればフレームワーク内のクラスを使用することをお勧めしますが、スレッド化をよりよく理解するためにこれを書いていることを願っています。

于 2011-05-22T18:35:06.623 に答える
3

あなたは使用することによってはるかに簡単な方法であなたの目標を達成することができます

java.util.concurrent.locks.ReentrantReadWriteLock

読み取りを開始するときはjava.util.concurrent.locks.ReentrantReadWriteLock.ReadLockを取得し、書き込みを開始するときはjava.util.concurrent.locks.ReentrantReadWriteLock.WriteLockを取得します。

このクラスはまさにそのためのものです。単一のライターと相互に排他的な複数のリーダーを許可します。

于 2011-05-22T18:42:58.837 に答える
2

の特定の実装はread_start、単にメソッドを宣言することと同じではありませんsynchronized。J. Skeedが指摘したように、使用しているオブジェクトを呼び出すnotify(および)必要があります。これには、無関係のオブジェクト(ここではクラス)を使用できません。また、メソッドで変更を使用しても、メソッドが暗黙的に呼び出されることはありません。waitsynchronizesynchronizedwait

ところで、コアJDKに同梱されている読み取り/書き込みロックの実装がありますjava.util.concurrent.locks.ReentrantReadWriteLock。これを使用すると、コードは代わりに次のようになります。

class Resource {
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private final Lock rlock = lock.readLock();
    private final Lock wlock = lock.writeLock();

    void read() { ... /* caller has to hold the read lock */ ... }
    void write() { ... /* caller has to hold the write lock */ ... }

    Lock readLock() { return rlock; }
    Lock writeLock() { return wlock; }
}

使用法

final Resource r = ...;

r.readLock().lock();
try {
    r.read();
} finally {
    r.unlock();
}

書き込み操作についても同様です。

于 2011-05-22T18:40:57.497 に答える
0

サンプル コードは で同期します。これにより、同じクラス ローダー内の の複数のインスタンスに対してthis.getClass()同じオブジェクトが返されます。の複数のインスタンスが存在する場合、複数のスレッドがあっても、この共有ロックで競合が発生します。これは、(Jon Skeet が提案したように) プライベート ロック フィールドにキーワードを追加することに似ており、またはプライベート ロック オブジェクトで同期するよりもパフォーマンスが低下する可能性があります。より具体的には、読み取り中のスレッドが書き込み中の別のスレッドをブロックする可能性があり、これは望ましくない可能性があります。ClassReadersWritersReadersWritersstaticthis

于 2011-05-22T18:59:03.573 に答える