4

書き込みメソッドが実行されていない限り、任意の数のスレッドが実行できるように、読み取りメソッドを同期する必要がある同期演習があります。これはゼロから行う必要があるため、java.util.concurrent.locks ect を使用できません。

このために、読み取りメソッドをブロックするのではなく、保護するための何らかのメカニズムが必要です。そのため、読み取りスレッドは書き込みによってブロックされますが、他の読み取りによってはブロックされません。読み取りメソッドでロック メソッドを呼び出すと、他の読み取りスレッドが待機するため、通常のロックは使用できません。

ルールは次のとおりです。スレッドが write() 内にある場合、他のスレッドは read() または write() に入ってはなりません。スレッドが read() 内にある場合、他のスレッドは write() に入ってはいけませんが、入ることはできます読んだ()

この問題に対処するために、自家製のロックをいくつか作成してみました。WriteLock はかなり標準的な再入可能ロックですが、read が実行されている場合はブロックされます (readcounter を使用します)。それ以外の場合は、スレッドが本来の業務を遂行できるようにし、WriteLocks カウンターをインクリメントする必要があります。

コード:

package sync;

public class SyncTest {
    Long testlong = new Long(0L);
    int reads = 0;
    int writes = 0;
    WriteLock w = new WriteLock();
    ReadLock r = new ReadLock(w);

    public SyncTest() {
        // TODO Auto-generated constructor stub
    }

    public static void main(String args[]){

        final SyncTest s = new SyncTest();

        for(int i = 0 ; i<3 ; i++){ //Start a number of threads to attack SyncTest
            final int ifinal = i;
            new Thread(){
                int inc = ifinal;
                @Override
                public void run() {
                    System.out.println("Starting "+inc);
                    long starttime = System.currentTimeMillis();
                    try {
                    while(System.currentTimeMillis()-starttime < 10){

                        if (inc < 2){

                            s.readLong();

                        }else{
                            s.writeLong(inc+1);
                        }
                    }
                    System.out.println(inc + " done");
                    if(inc == 0){
                        Thread.sleep(1000);
                        System.out.println(s.reads+" "+s.writes);
                    }
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                    // TODO Auto-generated method stub

                }
                @Override
                public String toString() {
                    // TODO Auto-generated method stub
                    return "Thread "+inc+" "+super.toString();
                }



            }.start();
        }
    }

    public Long readLong() throws InterruptedException{

        Long l;
        r.lock(); //Lock for reading
        //System.out.println("Read "+reads);
        l =  testlong;
        reads++;
        r.unlock(); //Unlock after reading
        return l;   
        }

    public void writeLong(int i) throws InterruptedException{

        w.lock(); //Lock for writing
        //System.out.println("Write "+writes);
        int curreads = reads;
        int curwrites = writes;
        testlong = testlong + i;
        writes++;

        Thread.sleep(100); //Simulate long write
        if(curreads != reads){
            System.out.println("Reads did not lock");
        }

        if(curwrites+1 != writes){
            System.out.println("Writes did not lock");
        }
        w.unlock(); //Unlock writing
    }

    protected class WriteLock{
        boolean isLocked = false;
        Thread lockedBy = null;
        int lockedCount = 0;
        int readers = 0; //The number of readers currently through the reading lock.

        public synchronized void lock() throws InterruptedException {
            System.out.println("Locking: "+Thread.currentThread());
            Thread callingThread = Thread.currentThread();
            while ((isLocked && lockedBy != callingThread) || readers > 0) { //Wait if locked or readers are in read()
                wait();
            }
            isLocked = true;
            lockedCount++;
            lockedBy = callingThread;
            System.out.println("Is locked: "+Thread.currentThread());
        }

        public synchronized void unlock() {
            //System.out.println("Unlocking: "+Thread.currentThread());
            if (Thread.currentThread() == this.lockedBy) {
                lockedCount--;

                if (lockedCount == 0) {
                    System.out.println("Is unlocked: "+Thread.currentThread());
                    isLocked = false;
                    notify();
                }
            }
        }

    }

    protected class ReadLock{
        WriteLock lock;

        public ReadLock(WriteLock lock) {
            super();
            this.lock = lock;
        }

        public synchronized void lock() throws InterruptedException { //If write() then wait
            System.out.println("Waiting to read: "+Thread.currentThread());
            Thread callingThread = Thread.currentThread();
            while (lock.isLocked && lock.lockedBy != callingThread) {
                wait();
            }
            lock.readers++; //Increment writelocks readers
            System.out.println("Reading: "+Thread.currentThread());

        }

        public synchronized void unlock() {
            lock.readers--; //Subtract from writelocks readers
            notify();
        }

    }

}

これは機能しませんが、読み取りロックは、スレッドが書き込み中にリーダーをロックするほど機能しますが、WriteLock がロック解除されたときにリーダーを解放しません。

これは概念的に正しくないのでしょうか、それともモニターで理解できないことがありますか? または、他の何か?

4

2 に答える 2

15

(質問が演習であるという点で編集される前に回答されました。)

ReadWriteLock実装を希望しているようです。

ReadWriteLock は、関連付けられたロックのペアを維持します。1 つは読み取り専用操作用で、もう 1 つは書き込み操作用です。読み取りロックは、ライターがない限り、複数のリーダー スレッドによって同時に保持される場合があります。書き込みロックは排他的です。

1 つの実装はReentrantReadWriteLock.

特に並行性については、独自のコードを実装する前に、既存のライブラリ ( et al) を調べる価値がありjava.util.concurrentます。あなたが私のような人であれば、同時実行性の点で正しくすることができたとしても、専門家によって書かれたコードほど効率的ではありません...そしてもちろん、最初からすべての作業です;)

于 2013-02-01T14:40:28.963 に答える
1

ReadLock と WriteLock は異なるオブジェクトで同期しており、異なるオブジェクトで待機と通知を呼び出しています。

これにより、WriteLock がカウントを検証している間に、ReadLock が WriteLock のカウントを変更できるようになります。また、別のロックが呼び出しから復帰しない原因にもなります。

ReadLock を変更して WriteLock をモニターとして使用すると、より良い結果が得られます (これが唯一の問題かどうかは確認していません)。

protected class ReadLock{
    WriteLock lock;

    public ReadLock(WriteLock lock) {
        super();
        this.lock = lock;
    }

    public void lock() throws InterruptedException { //If write() then wait
        synchronized (lock) {
           System.out.println("Waiting to read: "+Thread.currentThread());
           Thread callingThread = Thread.currentThread();
           while (lock.isLocked && lock.lockedBy != callingThread) {
               lock.wait();
           }
           lock.readers++; //Increment writelocks readers
           System.out.println("Reading: "+Thread.currentThread());
       }
    }

    public void unlock() {
        synchronized (lock) {
           lock.readers--; //Subtract from writelocks readers
           lock.notify();
        }
    }

}
于 2013-02-01T21:03:25.353 に答える