Программа чтения и записи Java с первым вводом-выводом

#java #multithreading #concurrency #fifo

#java #многопоточность #параллелизм #fifo

Вопрос:

Здесь мы создали параллельную программу на Java, в которой мы моделируем базу данных, из которой мы читаем и записываем в нее. У нас есть 20 читателей, которые читают одновременно, и 2 писателя, которые этого не делают.

Читатели начинают читать, и после того, как они закончат, авторы начинают писать, что вызывает голод у авторов.

Результат, который я получаю:

 Reader 15 started reading
Reader 5 started reading
Reader 2 started reading
Reader 7 started reading
Reader 15 finished reading
Reader 5 finished reading
Reader 16 started reading
...
...
Writer 21 started writing
Writer 21 finished writing
Writer 20 started writing
Writer 20 finished writing
 

Итак, я пытался внедрить порядок FIFO в эту программу, чтобы убить это голодание. например, выходные данные должны быть R1, W1, R2, R3, R4, W2 (R — reader, W— writer). Я застрял на этом этапе, и я не знаю, менять ли мой алгоритм или нет. Заранее спасибо!

 import java.util.concurrent.ThreadLocalRandom;

public class Runner {
    public static void main(String[] args) {
        try {
            runDB(20, 2, new BetterDB());
        } catch (InterruptedException ignored){}
    }

    static void runDB(int readersAmount, int writersAmount, DB database) throws InterruptedException {
        assert readersAmount > 0;
        assert writersAmount > 0;

        Thread[] threads = new Thread[readersAmount   writersAmount];

        for (int i = 0; i < readersAmount; i  ){
            threads[i] = new Thread(new Reader(database, i));
        }
        for (int i = readersAmount; i <  readersAmount   writersAmount; i  ){
            threads[i] = new Thread(new Writer(database, i));
        }

        for (Thread thread : threads){
            thread.start();
        }
        for (Thread thread : threads){
            thread.join();
        }
    }
}

interface DB {
    void read(int readerID) throws InterruptedException;
    void write(int writerId);
}

class BetterDB implements DB {
    long READ_TIME = 500; // milliseconds
    long WRITE_TIME = 1000; // milliseconds

    int readers = 0;

    @Override
    public void read(int readerID) throws InterruptedException {
        synchronized (this) {
            readers  ;
            System.out.printf("Reader %d started readingn", readerID);
        }

        try {
            ThreadLocalRandom random = ThreadLocalRandom.current();
            Thread.sleep(random.nextLong(READ_TIME));
        } catch (InterruptedException ignored) {}

        synchronized (this) {
            readers--;
            System.out.printf("Reader %d finished readingn", readerID);
            if (readers == 0) {
                this.notifyAll();
            }
        }
    }

    @Override
    public synchronized void write(int writerId) {
        try{
            while(readers > 0){
                this.wait();
            }
        } catch (InterruptedException ignored) {}

        System.out.printf("Writer %d started writingn", writerId);
        try{
            ThreadLocalRandom random = ThreadLocalRandom.current();
            Thread.sleep(random.nextLong(WRITE_TIME));
        } catch (InterruptedException ignored) {}

        System.out.printf("Writer %d finished writingn", writerId);
    }
}


class Reader implements Runnable {
    final long READER_DELAY = 500; // milliseconds
    private final DB database;
    private int id;

    Reader(DB database, int id){
        this.database = database;
        this.id = id;
    }

    @Override
    public void run() {
        try{
            ThreadLocalRandom random = ThreadLocalRandom.current();
            Thread.sleep(random.nextLong(READER_DELAY));
            database.read(id);
        } catch (InterruptedException ignored) {}
    }
}

class Writer implements Runnable {
    final long WRITER_DELAY = 400; // milliseconds
    private final DB database;
    private int id;

    Writer(DB database, int id){
        this.database = database;
        this.id = id;
    }

    @Override
    public void run() {
        try{
            ThreadLocalRandom random = ThreadLocalRandom.current();
            Thread.sleep(random.nextLong(WRITER_DELAY));
            database.write(id);
        } catch (InterruptedException ignored) {}
    }
}
 

Комментарии:

1. Итак, вы хотите, чтобы некоторые операции записи и чтения были смешаны?

Ответ №1:

Итак, если я понимаю, что вы пытаетесь, вы хотите, чтобы ваши авторы могли приостанавливать чтение, чтобы у них действительно была возможность писать?

Прямо сейчас они перегружены. Все читатели могут оставаться занятыми сколько угодно, потому что их 20, и все они могут выполняться одновременно, и вероятность того, что все они будут останавливаться достаточно долго, чтобы писатель перехватил синхронизированную блокировку, очень и очень мала.

Похоже, вам нужно реализовать более сложную блокировку, такую как блокировка «запросить две записи». Вы можете заставить своих авторов увеличивать блокировку, а затем уменьшать ее, когда они закончат. Читателям потребуется аналогичная логика, которую авторы проверяют, чтобы увидеть, есть ли запрос на блокировку записи.