【问题标题】:Java: How to solve Readers-Writer Problem?Java:如何解决读写器问题?
【发布时间】:2021-04-15 01:00:00
【问题描述】:

我想为 Readers-Writer 问题实施解决方案。主要规则是,一次只有一个写入者可以写入,其他写入者或读取者都不能写入或读取,但如果写入者不写入,则多个读取者可以读取。在主类中,我尝试使用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

【问题讨论】:

    标签: java multithreading concurrency parallel-processing synchronization


    【解决方案1】:

    程序永远不会结束,我猜有一些输出问题。

    ReadWriteLock 类中添加一个标志,以在Threads 应该停止工作时发出信号:

    private final AtomicBoolean keep_working = new AtomicBoolean(true);
    

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

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

    并添加查询标志的方法:

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

    相应地调整WriterReader run 方法:

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

    main 类上添加对方法 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();
    }
        
    

    我认为这个问题的输出不正确: (...) 在此输出中,有 2 位作家同时写作。

    那是因为在:

    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();
        }
    

    主要规则是,一次只能由一位作家写作,而不能有其他作家 writer 或 reader 可以写或读,但如果 writer 不写, 多个读者可以阅读。

    实际上,您可以利用 Java ReadWriteLock 接口。

    ReadWriteLock 维护一对关联的锁,一个用于 只读操作和一个用于写入的操作。读锁可能被持有 同时由多个阅读器线程,只要没有 writers。 写锁是独占的。所有读写锁 实现必须保证内存同步效果 的 writeLock 操作(在 Lock 接口中指定)也持有 关于关联的 readLock。也就是一个线程 成功获取读锁将看到所有更新 之前释放的写锁。

    读写锁允许更高级别的并发 访问共享数据而不是互斥锁允许的访问。 它利用了这样一个事实,即虽然一次只有一个线程(一个 writer thread) 可以修改共享数据,在很多情况下任意数量的 线程可以同时读取数据(因此读取器线程)。在 理论上,通过使用一个允许的并发性增加 读写锁将导致性能比使用 互斥锁。在实践中,这种并发性的增加将 只有在多处理器上才能完全实现,然后只有当 共享数据的访问模式是合适的。

    通过使用该接口,您可以显着简化 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 线程应该写入一些东西,等等。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        猜你喜欢
        • 2014-06-26
        • 1970-01-01
        • 2021-01-22
        • 1970-01-01
        • 2020-01-30
        • 1970-01-01
        • 2021-04-09
        • 2021-08-24
        • 1970-01-01
        相关资源
        最近更新 更多