Читатели писатели проблемы параллельной Java - PullRequest
2 голосов
/ 22 мая 2011

Это реализация читателей-писателей, то есть многие читатели могут читать, но только один писатель может писать одновременно.Это работает как ожидалось?

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 ]

6 голосов
/ 22 мая 2011

Нет - вы неявно звоните this.wait(), несмотря на то, что вы не синхронизировались на this, а вместо этого в классе. Точно так же вы звоните this.notifyAll() в read_end. Мои предложения:

  • Не расширять Thread - вы вообще не специализируете нить.
  • Не использовать статические переменные, подобные этим, от членов экземпляра; выглядит как будто есть состояние для каждого объекта, но на самом деле его нет. Лично я бы просто использовал переменные экземпляра.
  • Не используйте подчеркивания в именах - обычные имена Java будут numReaders, readEnd (или лучше, endRead) и т. Д.
  • Не синхронизируйте ни на this, ни на классе, если вы можете помочь. Лично я предпочитаю иметь переменную private final Object для блокировки (и ожидания и т.д.). Таким образом, вы знаете, что может синхронизироваться только ваш код , что облегчает рассуждения.
  • Вы никогда не устанавливаете writing в 0. Есть ли причина использовать целое число вместо boolean в первую очередь?

Конечно, для этого лучше использовать классы в фреймворке, если это вообще возможно - но я надеюсь, что вы действительно пишете это, чтобы лучше понимать многопоточность.

3 голосов
/ 22 мая 2011

Вы можете достичь своей цели намного проще, используя

java.util.concurrent.locks.ReentrantReadWriteLock

Просто возьмите java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock, когда вы начнете читать, и java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock, когда вы начнете писать.

Этот класс предназначен именно для этого - разрешить нескольким читателям, которые являются взаимоисключающими с одним писателем.

2 голосов
/ 22 мая 2011

Ваша конкретная реализация read_start не эквивалентна простому объявлению метода synchronized.Как отметил Дж. Скид, вам нужно вызвать notifywait) для объекта, с которым вы synchronize работаете.Вы не можете использовать не связанный объект (здесь: класс) для этого.И использование synchronized, модифицированного для метода, не заставляет метод неявно вызывать wait или что-то в этом роде.

Кстати, есть реализация блокировок чтения / записи, которая поставляется с ядром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();
}

и аналогичный для операции записи.

0 голосов
/ 22 мая 2011

Пример кода синхронизируется с this.getClass(), что возвращает один и тот же объект Class для нескольких экземпляров ReadersWriters в одном загрузчике классов.Если существует несколько экземпляров ReadersWriters, даже если у вас несколько потоков, возникнет конфликт для этой общей блокировки.Это было бы похоже на добавление ключевого слова static в поле частной блокировки (как предположил Джон Скит) и, вероятно, привело бы к ухудшению производительности, чем синхронизация на this или объекте частной блокировки.Более конкретно, один поток, который читает, будет блокировать другой поток, который пишет, и это, вероятно, нежелательно.

...