Java实现读者写者问题--读者优先

作者:凌杰林

简介

临界资源:同一时间只能由一个进程访问的资源

临界区:访问临界资源的代码段

读者写者问题:存在一个多个进程共享的数据区(临界资源),该数据区可以是一个文件或者一块内存空间,甚至可以是一组寄存器;有些进程reader只读取这个数据区的数据,有些进程writer只往数据区中写数据。此外,还需要满足以下条件:

1.任意数量的读进程可以同时读这个文件。

2.一次只能有一个写进程可以写这个文件。

3.若一个写进程正在写文件,则禁止任何读进程读文件。

4.读者优先:必须等所有读进程读完才可以写。

也即是说,读进程不排斥其它读进程,而写进程排斥其它所有进程,包括读进程和写进程。

分析

在这里插入图片描述

类的编写

Semaphore类

利用Java的多线程编程实现,操作系统中的p,v操作。p,v操作的函数添加synchronized关键字,加锁,确保同一时刻只有一个进程可以操作semValue这个临界资源,否则多个进程同时访问该值,会出现错误。

public class Semaphore{
    private int semValue;
    //定义信号量
    public Semaphore(int semValue) {
        this.semValue = semValue;
    }
    public synchronized void p() {
        semValue--;
        if (semValue < 0) {
            try {
                this.wait();//阻塞该进程
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public synchronized void v(){
        semValue++;
        if (semValue <= 0) {
            this.notify();//唤醒被阻塞的进程
        }
    }
}

Reader类

定义读者类,实现Runnable接口,重写run方法。

class Reader implements Runnable{
	private Semaphore rmutex,wmutex;
	My my;
	static int readcount = 0;
	public Reader(Semaphore rmutex,Semaphore wmutex,My my){
		this.rmutex = rmutex;
		this.wmutex = wmutex;
		this.my = my;
	}
	@Override
	public void run() {
			try{
				Thread.sleep((int)(1000*my.arrive_time));
			}catch (InterruptedException e){e.printStackTrace();}
		    System.out.println("线程" + my.thread + "申请读操作");
			rmutex.p();
			if (readcount == 0) wmutex.p();
			readcount++;
			rmutex.v();
		    System.out.println("线程" + my.thread + "开始读操作");
			try{
				Thread.sleep((int)(1000*my.operate_time));
			} catch (InterruptedException e){
				e.printStackTrace();
			}
			rmutex.p();
			readcount--;
			System.out.println("线程" + my.thread + "结束读操作");
		    if (readcount == 0) wmutex.v();
			rmutex.v();
	}
}

细节

实现读者优先,定义readcount变量,初始值为0,用于记录当前读者进程的数量,第一个读者负责上锁,防止写进程申请资源,最有一个读进程负责解锁,唤醒被阻塞的写进程

Writer类

定义写者类,实现Runnable接口,重写run方法。

class Writer implements Runnable{
	private Semaphore wmutex;
	My my;
	public Writer(Semaphore wmutex,My my){
		this.wmutex = wmutex;
		this.my = my;
	}
	@Override
	public void run() {
		try{
			Thread.sleep((int)(1000*my.arrive_time));
		}catch (InterruptedException e){e.printStackTrace();}
		System.out.println("线程" + my.thread + "申请写操作");
		wmutex.p();
		System.out.println("线程" + my.thread + "开始写操作");
		try{
			Thread.sleep((int)(1000*my.operate_time));
		}catch (InterruptedException e){e.printStackTrace();}
		wmutex.v();
		System.out.println("线程" + my.thread + "完成写操作");
	}
}

其他类

该类定义了一个进程的编号,到达时间,读/写类型,要求服务时间。

class My
{
	int thread;
	String type;
	double arrive_time;
	double operate_time;
	My(String s)
	{
		StringTokenizer st=new StringTokenizer(s);
		thread = Integer.parseInt(st.nextToken());
		type = st.nextToken();
		arrive_time = Double.parseDouble(st.nextToken());
		operate_time = Double.parseDouble(st.nextToken());
	}

该类是主类

import java.io.*;
import java.util.*;
public class ReaderWriter
{
	public static void main(String[] args) 
	{
		Semaphore wmutex = new Semaphore(1);
		Semaphore rmutex = new Semaphore(1);
		int i;
		String s=null;
		My m[]=new My[10];
		try{
			BufferedReader br=new BufferedReader(new FileReader("Input.txt"));
			for (i=0;(s=br.readLine())!=null;i++) 
			{
				m[i]=new My(s);
				System.out.println("线程"+m[i].thread+"是"+m[i].type+"线程,第"+m[i].arrive_time+"秒申请读写操作,操作持续"+m[i].operate_time+"秒");
				if (m[i].type.equals("R")){
					new Thread(new Reader(rmutex,wmutex,m[i])).start();
				}
				else {
					new Thread(new Writer(wmutex,m[i])).start();
				}
			}
		}
		catch(IOException e){}	
	}
}

数据格式

1 R 1 5

2 W 3 4

数据存储在同目录下的input.txt文件中。

源代码

public class Semaphore{
    private int semValue;
    public Semaphore(int semValue) {
        this.semValue = semValue;
    }
    public synchronized void p() {
        semValue--;
        if (semValue < 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public synchronized void v(){
        semValue++;
        if (semValue <= 0) {
            this.notify();
        }
    }
}



//另外一个类
import java.io.*;
import java.util.*;
public class ReaderWriter
{
	public static void main(String[] args) 
	{
		Semaphore wmutex = new Semaphore(1);
		Semaphore rmutex = new Semaphore(1);
		int i;
		String s=null;
		My m[]=new My[10];
		try{
			BufferedReader br=new BufferedReader(new FileReader("Input.txt"));
			for (i=0;(s=br.readLine())!=null;i++) 
			{
				m[i]=new My(s);
				System.out.println("线程"+m[i].thread+"是"+m[i].type+"线程,第"+m[i].arrive_time+"秒申请读写操作,操作持续"+m[i].operate_time+"秒");
				if (m[i].type.equals("R")){
					new Thread(new Reader(rmutex,wmutex,m[i])).start();
				}
				else {
					new Thread(new Writer(wmutex,m[i])).start();
				}
			}
		}
		catch(IOException e){}	
	}
}
class Reader implements Runnable{
	private Semaphore rmutex,wmutex;
	My my;
	static int readcount = 0;
	public Reader(Semaphore rmutex,Semaphore wmutex,My my){
		this.rmutex = rmutex;
		this.wmutex = wmutex;
		this.my = my;
	}
	@Override
	public void run() {
			try{
				Thread.sleep((int)(1000*my.arrive_time));
			}catch (InterruptedException e){e.printStackTrace();}
		    System.out.println("线程" + my.thread + "申请读操作");
			rmutex.p();
			if (readcount == 0) wmutex.p();
			readcount++;
			rmutex.v();
		    System.out.println("线程" + my.thread + "开始读操作");
			try{
				Thread.sleep((int)(1000*my.operate_time));
			} catch (InterruptedException e){
				e.printStackTrace();
			}
			rmutex.p();
			readcount--;
			System.out.println("线程" + my.thread + "结束读操作");
		    if (readcount == 0) wmutex.v();
			rmutex.v();
	}
}
class Writer implements Runnable{
	private Semaphore wmutex;
	My my;
	public Writer(Semaphore wmutex,My my){
		this.wmutex = wmutex;
		this.my = my;
	}
	@Override
	public void run() {
		try{
			Thread.sleep((int)(1000*my.arrive_time));
		}catch (InterruptedException e){e.printStackTrace();}
		System.out.println("线程" + my.thread + "申请写操作");
		wmutex.p();
		System.out.println("线程" + my.thread + "开始写操作");
		try{
			Thread.sleep((int)(1000*my.operate_time));
		}catch (InterruptedException e){e.printStackTrace();}
		wmutex.v();
		System.out.println("线程" + my.thread + "完成写操作");
	}
}
class My
{
	int thread;
	String type;
	double arrive_time;
	double operate_time;
	My(String s)
	{
		StringTokenizer st=new StringTokenizer(s);
		thread = Integer.parseInt(st.nextToken());
		type = st.nextToken();
		arrive_time = Double.parseDouble(st.nextToken());
		operate_time = Double.parseDouble(st.nextToken());
	}
	}

小结

读者-写者问题为我们解决互斥问题提供了一种参考思路,核心的思想时,在于设置一个计数器readcount记录当前正在访问共享文件的进程数目,用readcount的值来判断是否为最后一个或者最先一个读者进程,从而实现加锁或者解锁。另外,对readcount的检查和赋值操作要一气呵成,就是“原子性”,这时候,我们就应该想到要用操作系统课中的P,V操作来实现,设置好互斥的相关操作,构造好该信号量的类。

  • 9
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值