Java:如何解决读写器问题?

标签 java multithreading concurrency parallel-processing synchronization

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

最佳答案

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


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()){
           ...
        }
    }
在主类上添加对方法的调用 ExecutorService.awaitTermination() , ReadWriteLock.stopThreads , 和 ExecutorService.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();
    }
要完成,您应该添加一个计算写入和读取次数的变量。因此,如果没有写入任何内容,则读取线程应该等待,同时,写入线程应该写入一些东西,依此类推。

关于Java:如何解决读写器问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65643920/

相关文章:

java - Java中如何同步访问类字段?

Android 后台服务类 "onStartCommand"方法在设备启动时不执行其中的所有代码

Java:使用 Swing 编写游戏

java - 为什么通过 newCachedThreadPool 创建的 ExecutorService 是邪恶的?

Java Servlet请求的并发问题

sql-server - SQL Server 意图锁是如何工作的?

java - 无法使用代码录制屏幕

java - 如何为 RabbitMQ DefaultConsumer 设置超时?

java - hibernate 中缺少@Temporal 注释

java - 如何将 Collection<Number> 转换为 Collection<Integer> 安全?