Java: Readers-Writer Problem 如何解决?

Java: How to solve Readers-Writer Problem?

我想为读写器问题实施一个解决方案。主要规则是,一次只有一个作者可以写,其他作者或 reader 不能写或读,但是如果一个作者不写,多个 reader 可以读。在主要 class 中,我尝试使用 executorService.execute 运行 线程,但我猜我遇到了一些问题。我对executorService了解不多。程序永远不会结束,我猜有一些输出问题。

我的代码如下:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;


public class ReaderWriter {
public static void main(String [] args) {
    ExecutorService executorService = Executors.newCachedThreadPool();
    ReadWriteLock RW = new ReadWriteLock();


    executorService.execute(new Writer(RW));
    executorService.execute(new Writer(RW));
    executorService.execute(new Writer(RW));
    executorService.execute(new Writer(RW));

    executorService.execute(new Reader(RW));
    executorService.execute(new Reader(RW));
    executorService.execute(new Reader(RW));
    executorService.execute(new Reader(RW));
 }
}


class ReadWriteLock{
    static Semaphore readLock = new Semaphore(1);
    static Semaphore writeLock = new Semaphore(1);
    volatile static int readCount = 0;

    public void readLock() throws InterruptedException {

        readLock.acquire();
        readCount++;
        if (readCount == 1) {
            writeLock.acquire();
        }
        readLock.release();

        //Reading section
        System.out.println("Thread "+Thread.currentThread().getName() + " is READING");
        Thread.sleep(1500);
        System.out.println("Thread "+Thread.currentThread().getName() + " has FINISHED READING");

        //Releasing section
        readLock.acquire();
        readCount--;
        if(readCount == 0) {
            writeLock.release();
        }
        readLock.release();
    }
    public void writeLock() throws InterruptedException {
        writeLock.acquire();
        System.out.println("Thread "+Thread.currentThread().getName() + " is WRITING");
        Thread.sleep(2500);
        writeLock.release();
        System.out.println("Thread "+Thread.currentThread().getName() + " has finished WRITING");
    }
}




class Writer implements Runnable
{
    private ReadWriteLock RW_lock;


    public Writer(ReadWriteLock rw) {
        RW_lock = rw;
    }

    public void run() {
        while (true){
            try {
                RW_lock.writeLock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}



class Reader implements Runnable
{
    private ReadWriteLock RW_lock;


    public Reader(ReadWriteLock rw) {
        RW_lock = rw;
    }
    public void run() {
        while (true){
            try {
                RW_lock.readLock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


}

对于这个问题,我认为输出不正确:

Thread pool-1-thread-1 is WRITING
Thread pool-1-thread-2 is WRITING
Thread pool-1-thread-1 has finished WRITING
Thread pool-1-thread-2 has finished WRITING
Thread pool-1-thread-3 is WRITING
Thread pool-1-thread-3 has finished WRITING
Thread pool-1-thread-4 is WRITING
Thread pool-1-thread-4 has finished WRITING
Thread pool-1-thread-5 is READING
Thread pool-1-thread-8 is READING
Thread pool-1-thread-7 is READING
Thread pool-1-thread-6 is READING
Thread pool-1-thread-8 has FINISHED READING
Thread pool-1-thread-5 has FINISHED READING
Thread pool-1-thread-8 is READING
Thread pool-1-thread-5 is READING
Thread pool-1-thread-6 has FINISHED READING
Thread pool-1-thread-6 is READING
Thread pool-1-thread-7 has FINISHED READING
Thread pool-1-thread-7 is READING
Thread pool-1-thread-5 has FINISHED READING
Thread pool-1-thread-5 is READING
Thread pool-1-thread-8 has FINISHED READING

在此输出中有 2 个作者同时写入。

输出编辑:

Thread pool-1-thread-1 is WRITING
Thread pool-1-thread-1 has finished WRITING
Thread pool-1-thread-1 is WRITING
Thread pool-1-thread-1 has finished WRITING
Thread pool-1-thread-4 is WRITING
Thread pool-1-thread-4 has finished WRITING
Thread pool-1-thread-3 is WRITING
Thread pool-1-thread-3 has finished WRITING
Thread pool-1-thread-2 is WRITING
Thread pool-1-thread-2 has finished WRITING
Thread pool-1-thread-8 is READING
Thread pool-1-thread-7 is READING
Thread pool-1-thread-5 is READING
Thread pool-1-thread-6 is READING
Thread pool-1-thread-8 has FINISHED READING
Thread pool-1-thread-7 has FINISHED READING
Thread pool-1-thread-5 has FINISHED READING
Thread pool-1-thread-6 has FINISHED READING

需要在main方法中调用ExecutorService的shutdown或shutdownAndAwaitTermination方法

The program never ends and i guess there is some output problems.

ReadWriteLock class 中添加一个 标志 以向 Threads 发出停止工作的信号:

private final AtomicBoolean keep_working = new AtomicBoolean(true);

ReadWriteLock class 中添加一个方法来通知线程停止:

public void stopThreads(){
    keep_working.set(false);
}

并添加查询标志的方法:

public boolean keepWorking(){
    return keep_working.get();
}

相应地调整 WriterReader run 方法:

 public void run() {
        while (RW_lock.keepWorking()){
           ...
        }
    }

main class 添加对方法 ExecutorService.awaitTermination()ReadWriteLock.stopThreadsExecutorService.shutdown() 的调用:

public static void main(String [] args) {
    ExecutorService executorService = Executors.newCachedThreadPool();
    ReadWriteLock RW = new ReadWriteLock();

    executorService.execute(new Writer(RW));
    executorService.execute(new Writer(RW));
    executorService.execute(new Writer(RW));
    executorService.execute(new Writer(RW));

    executorService.execute(new Reader(RW));
    executorService.execute(new Reader(RW));
    executorService.execute(new Reader(RW));
    executorService.execute(new Reader(RW));
    try {
        executorService.awaitTermination(5, TimeUnit.SECONDS);
    } catch (InterruptedException e) { // ...} 
    RW.stopThreads();
    executorService.shutdown();
}
    

And the output is not right i think for this problem: (...) In this output there is 2 writers writing at the same time.

那是因为在 :

public void writeLock() throws InterruptedException {
    writeLock.acquire();
    System.out.println("Thread "+Thread.currentThread().getName() + " is WRITING");
    Thread.sleep(2500);
    writeLock.release();
    System.out.println("Thread "+Thread.currentThread().getName() + " has finished WRITING");
}

你在打印之前释放了锁 “已完成写入” 因此,等待该锁被释放的线程在第一个线程有时间之前进入并打印“正在写入”打印 "已完成写入"。所以需要把代码改成:

   public void writeLock() throws InterruptedException {
        writeLock.acquire();
        System.out.println("Thread "+Thread.currentThread().getName() + " is WRITING");
        Thread.sleep(2500);
        System.out.println("Thread "+Thread.currentThread().getName() + " has finished WRITING");
        writeLock.release();
    }

The main rule is, only one writer can write at a time and no other writer or reader can write or read, but if a writer doesn't write , multiple readers can read.

实际上,您可以利用 Java ReadWriteLock 界面。

A ReadWriteLock maintains a pair of associated locks, one for read-only operations and one for writing. The read lock may be held simultaneously by multiple reader threads, so long as there are no writers. The write lock is exclusive. All ReadWriteLock implementations must guarantee that the memory synchronization effects of writeLock operations (as specified in the Lock interface) also hold with respect to the associated readLock. That is, a thread successfully acquiring the read lock will see all updates made upon previous release of the write lock.

A read-write lock allows for a greater level of concurrency in accessing shared data than that permitted by a mutual exclusion lock. It exploits the fact that while only a single thread at a time (a writer thread) can modify the shared data, in many cases any number of threads can concurrently read the data (hence reader threads). In theory, the increase in concurrency permitted by the use of a read-write lock will lead to performance improvements over the use of a mutual exclusion lock. In practice this increase in concurrency will only be fully realized on a multi-processor, and then only if the access patterns for the shared data are suitable.

通过使用该接口,您可以显着简化 readLockwriteLock 方法,如下所示:

   public void readLock() throws InterruptedException {
        shared_resource.readLock().lock();
        System.out.println("Thread "+Thread.currentThread().getName() + " is READING");
        Thread.sleep(1500);
        System.out.println("Thread "+Thread.currentThread().getName() + " has FINISHED READING");
        shared_resource.readLock().unlock();
    }
    public void writeLock() throws InterruptedException {
        shared_resource.writeLock().lock();
        System.out.println("Thread "+Thread.currentThread().getName() + " is WRITING");
        Thread.sleep(2500);
        System.out.println("Thread "+Thread.currentThread().getName() + " has finished WRITING");
        shared_resource.writeLock().unlock();
    }

要完成,您应该添加一个计算写入和读取次数的变量。因此,如果没有写入任何内容,read 线程应该等待,与此同时,write 线程应该写入一些内容,依此类推。