#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, и все они могут выполняться одновременно, и вероятность того, что все они будут останавливаться достаточно долго, чтобы писатель перехватил синхронизированную блокировку, очень и очень мала.
Похоже, вам нужно реализовать более сложную блокировку, такую как блокировка «запросить две записи». Вы можете заставить своих авторов увеличивать блокировку, а затем уменьшать ее, когда они закончат. Читателям потребуется аналогичная логика, которую авторы проверяют, чтобы увидеть, есть ли запрос на блокировку записи.