【问题标题】:First-In-First-out reader writer Java先进先出读写器 Java
【发布时间】:2020-12-07 00:46:32
【问题描述】:

在这里,我们用 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 reading\n", readerID);
        }

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

        synchronized (this) {
            readers--;
            System.out.printf("Reader %d finished reading\n", 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 writing\n", writerId);
        try{
            ThreadLocalRandom random = ThreadLocalRandom.current();
            Thread.sleep(random.nextLong(WRITE_TIME));
        } catch (InterruptedException ignored) {}

        System.out.printf("Writer %d finished writing\n", 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) {}
    }
}

【问题讨论】:

  • 所以你想让一些写入和读取混合?

标签: java multithreading concurrency fifo


【解决方案1】:

因此,如果我理解您的尝试,您希望您的作者能够暂停读者,以便他们真正有机会写作?

现在,他们不堪重负。读者可以随心所欲地保持忙碌,因为有 20 个,而且它们都可以同时运行,而且它们都会暂停足够长的时间让写者获取同步锁的可能性非常低。

听起来您需要实现更复杂的锁定,例如“请求两次写入”锁定。你可以让你的作者增加锁,然后在他们完成后减少它。读者需要与作者检查是否有写锁请求类似的逻辑。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多