java - Java:如何解决读写器问题?
问题描述
我想为读者 - 作家问题实施解决方案。主要规则是,一次只有一个写入者可以写入,其他写入者或读取者都不能写入或读取,但如果写入者不写入,则多个读取者可以读取。在主类中,我尝试运行线程,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
解决方案
该程序永远不会结束,我猜有一些输出问题。
在类中添加一个标志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();
}
相应地调整Writer
和Reader
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();
}
我认为这个问题的输出不正确:(...)在这个输出中,有 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();
}
主要规则是,一次只有一个写入者可以写入,其他写入者或读取者都不能写入或读取,但如果写入者不写入,则多个读取者可以读取。
实际上,您可以利用 Java ReadWriteLock接口。
ReadWriteLock 维护一对关联的锁,一个用于只读操作,一个用于写入。只要没有写者,读锁可能被多个读线程同时持有。写锁是独占的。所有 ReadWriteLock 实现必须保证 writeLock 操作的内存同步效果(如 Lock 接口中指定的那样)相对于关联的 readLock 也成立。也就是说,成功获取读锁的线程将看到在先前释放写锁时所做的所有更新。
与互斥锁相比,读写锁在访问共享数据时允许更高级别的并发性。它利用了这样一个事实:虽然一次只有一个线程(写入线程)可以修改共享数据,但在许多情况下,任意数量的线程可以同时读取数据(因此读取线程)。理论上,使用读写锁所允许的并发性的增加将导致比使用互斥锁的性能提高。在实践中,这种并发性的增加只有在多处理器上才能完全实现,而且只有在共享数据的访问模式合适的情况下。
通过使用该接口,您可以显着简化readLock
andwriteLock
方法,如下所示:
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();
}
要完成,您应该添加一个计算写入和读取次数的变量。因此,如果没有写入任何内容,则读取线程应该等待,同时,写入线程应该写入一些东西,依此类推。
推荐阅读
- ios - 如何设置来电显示或远程 pary id linphone?
- javascript - 如何使用 vee-validate 显示我的错误
- angular - 当我以角度请求我的数据库时,在我的数据列表上显示一条消息
- android - 在 3d 视图中显示时如何在设备屏幕中适合 3D 模型
- sql-server - 如何将单选按钮值保存到 SQLtable
- flutter - 处置后使用了 VideoPlayerController。一旦你在 VideoPlayerController 上调用了 dispose(),它就不能再使用了
- php - 在类中定义另一个伪变量(比如有 `$this` )
- reporting-services - 使用 TFS Web URL 处理warehousecontrolwebservice 时出错 (TFS-2018)
- azure - 用于审核 VM 磁盘信息的 PowerShell 脚本
- ios - 从左到右更改导航标题位置