Реализация Reader Writer в java - PullRequest
       4

Реализация Reader Writer в java

1 голос
/ 23 февраля 2020

Я пытался реализовать программу чтения-записи с использованием уведомлений и ожидания. Но я думаю, что застрял. Моя последовательность выглядит следующим образом. RRRRRRRRRRWWWWWWWWW Это происходит, если основной старт с ридером вызывается первым. Или WWWWWWWRRRRRRRRRRR. Это происходит, если основной старт с писателем вызывается первым. Похоже, что reads notify вообще не работает. Поток Writer никогда не переходит в исполнение.

Если я заставлю l oop в методе run работать бесконечно, то это просто RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR......... У писателя нет шансов написать. Можете ли вы взглянуть на это?

КЛАСС ДАННЫХ

public class Data {
    private int q ;
    private boolean isAnyOneReading;

    public Data() {
    }

    public  void readQ() {
        synchronized (this){
            isAnyOneReading = true;
            System.out.println("Read start "+q);
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        synchronized (this){
            isAnyOneReading = false;
            System.out.println("Read end "+q);
            notifyAll();
        }
    }

    public synchronized void writeQ(int q) {
        System.out.println(isAnyOneReading);
        while (isAnyOneReading){
            try{
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("Done");
                Thread.currentThread().interrupt();
            }
        }
        System.out.println("Write start "+q);
        this.q = q;
        try{
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
            Thread.currentThread().interrupt();
        }
        System.out.println("Write end "+q);
        notifyAll();
    }
}

КЛАСС ЧИТАТЕЛЯ

public class Reader implements  Runnable {
    private Data data;
    private Thread readerThread;


    public Reader(Data data) {
        this.data = data;
        readerThread = new Thread(this, "ReaderThread");
    }


    void startThread(){
        readerThread.start();
    }

    @Override
    public void run() {
        int i = 0 ;
        while (i != 5){
            data.readQ();
            i++;
        }
    }
}

КЛАСС ПИСАТЕЛЯ

public class Writer  implements  Runnable{
    private Data data;
    private Thread writerThread;

    public Writer(Data data) {
        this.data = data;
        writerThread = new Thread(this,"WriterThread," );
    }

    void startThread(){
        writerThread.start();
    }

    @Override
    public void run() {
        int i = 0 ;
        int j = 0 ;
        while (j != 5){
            data.writeQ(i++);
           // i++;
           j++;
        }
    }
}

ГЛАВНЫЙ КЛАСС

public class ReaderWriterDemo {
    public static void main(String[] args) {
        Data data = new Data();
        Reader reader = new Reader(data);
        Writer writer = new Writer(data);

        reader.startThread();
        writer.startThread();



    }
}

Ответы [ 3 ]

0 голосов
/ 23 февраля 2020

Read notifyAll () работает, но кажется, что read () вызывается снова и изменяет значение isAnyOneReading перед любым другим действием в write (). Вот почему проверка не проходит, и write () снова начинает ждать. Как предложил Дэнни Фрид, перемещение Thread.sleep () в методы run поможет.

0 голосов
/ 24 февраля 2020

Похоже на простой случай голодания. Рассмотрим основной писатель l oop:

    while (j != 5){
        data.writeQ(i++);
       // i++;
       j++;
    }

data.writeQ() - это метод synchronized: самое последнее, что он делает перед возвратом, это разблокирует блокировку. Самое первое, что он делает при следующем вызове, это повторно блокирует блокировку. Между ними мало что происходит - инкремент и проверка локальной переменной - это все.

Java synchronized блокировки не справедливые . (то есть, когда блокировка становится доступной, система не гарантирует, что победителем будет тот поток, который ждал дольше всего.) Фактически, это может быть напротив Справедливо: ОС может попытаться максимизировать эффективное использование ЦП, всегда выбирая поток, который легче всего активизировать.

Когда писатель возвращается к вызову data.writeQ() на каждой последующей итерации, он может будь то, что ОС даже не запустила запустил , чтобы разбудить читателя, и просто позволяет автору снова войти в блок synchronized.


То же самое происходит с вашим читателем , Код немного сложнее, но, как и в писателе, самое последнее, что data.readQ() делает перед возвратом, это разблокирует блокировку, и самое первое, что он делает при следующем вызове, - это снова блокирует его.


Решение методом грубой силы: замените блоки synchronized на справедливый ReentrantLock объект.

Альтернативное решение, более типично для того, сколько программ на самом деле работает: пусть потоки делают что-то еще (например, заставляют их выполнять некоторые операции ввода-вывода) между вызовами заблокированной функции, тем самым давая другим потокам возможность войти в и использовать заблокированный ресурс.

0 голосов
/ 23 февраля 2020

Попробуйте удалить Thread.sleep из класса Data. И добавьте Thread.sleep в методы запуска следующим образом. (вставляя один пример):

 @Override
public void run() {
    int i = 0;
    while (i != 5) {
        data.readQ();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            i++;
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...