java实现读者-写者问题

8 篇文章 1 订阅
1 篇文章 0 订阅

问题背景:一个数据文件或记录,可以被多个进程或者线程共享,其中不同的读进程可以并发的访问该临界资源,读和写进程或者线程,不能并发的对该临界资源进行操作,否则造成脏读和脏写,写和写进程之间也是互斥的。而我们今天的读者和写者模式 也称为读写锁,不过这里以信号量的方式进行互斥操作,就可以解决这个问题。
下面来看代码

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

public class RWTest {
    //创建一个用于记录正在读的读进程数
    static  int readCount=0;
    //创建一个读写线程共享的临界资源
    static  int sse=0;
    public static void main(String[] args) {
      //创建一个线程池
        ExecutorService es=Executors.newFixedThreadPool(10);
       //创建一个读写互斥的信号量
        final Semaphore wmutex=new Semaphore(1,true);

        //创建一个用于读进程间的修改临界资源readCount的互斥信号量
        final Semaphore rmutex=new Semaphore(1,true);
        //创建4个读进程
        for(int i=0;i<4;i++){
        es.execute(new Runnable(){

            @Override
            public void run() {
              while(!Thread.interrupted()){
                  try {

                    //获取可以修改readCount的互斥信号量
                    rmutex.acquire();
                //当readCount==0时说明,不存在读线程获得读写的互斥信号量,该信号量只对写线程操作互斥,对读线程不互斥
                    if(readCount==0){
                      //获取可以进行IO操作的的互斥信号
                        wmutex.acquire();
                    }

                    readCount++;
                    //释放信号量
                    rmutex.release();
                    //进行IO读操作
                    //这里我为了简单明了直接打印
                    System.out.println(Thread.currentThread().getId()+"正在进行读操作。。。。。。。。");
                    Thread.sleep(100);
                    System.out.println("读取的数据为"+sse);
                     //获取可以修改readCount的互斥信号量
                    rmutex.acquire();
                      readCount--;
                     //释放信号量
                    rmutex.release();
                    //当readCount==0时说明,所有读线程不再对共享资源进行操作了,则释放互斥信号量
                    if(readCount==0)
                    //释放信号量
                     wmutex.release();
                    //将cpu调度权让给其他读线程,但操作不一定成功
                      Thread.yield();

                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

              }
            }


        });
      }
    //创建3个写线程
        for(int i=0;i<3;i++){
            es.execute(new Runnable(){

                @Override
                public void run() {
                 while(!Thread.interrupted()){
                       try {
                        //获取可以进行IO操作的互斥信号量,防止其他读写线程对临界资源进行操作,如果获取不到,则等待
                        wmutex.acquire();           
                        //进行IO 写操作
                        //同样便于简单明了,这里只输出打印
                        System.out.println(Thread.currentThread().getId()+"正在进行写操作.........");
                        //修改临界资源的值
                               sse++;
                        //模拟IO操作所需时间
                             Thread.sleep(1000);
                        System.out.println("数据修改成功");
                        //释放信号量,让其他的读或写线程可以竞争
                         wmutex.release();
                         //将cpu的调度权让给其他写线程,但操作不一定成功
                          Thread.yield();

                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }



                 }

                }       
            });


        }


    }

}

结果分析:
我们代码中的无论读或写都不是原子操作的。
这里写图片描述
有上图可以看出读进程之间是不互斥的,可以并发访问。
这里写图片描述
有上图可以看出,读进程和写进程之间是互斥的,写进程和写进程之间也是互斥的。

  • 4
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
初始条件: 1操作系统:Linux 或者 windows 2程序设计语言:C,java语言 3设有20个连续的存储单元,写入/读出的数据项按增序设定为1-20这20个字符。 要求完成的主要任务: (包括课程设计工作量及其技术要求,以及说明书撰写等具体要求) 1.技术要求: 1)为每个读者写者产生一个线程,设计正确的同步算法 2)每个读者/写者对该存储区进行操作后,即时显示该存储区的全部内容、当前指针位置和读者/写者线程的自定义标识符。。 3)读者应有3个以上,写者应有有两个以上。 4)多个读者/写者之间须共享对存储区进行操作的函数代码。 2. 设计说明书内容要求: 1)设计题目与要求 2)总的设计思想及系统平台、语言、工具等。 3)数据结构与模块说明(功能与流程图) 4)给出用户名、源程序名、目标程序名和源程序及其运行结果。(要注明存储各个程序及其运行结果的主机IP地址和目录。) 5)运行结果与运行情况 (提示: (1)连续存储区可用数组实现。 (2)编译命令可用:     cc -lpthread -o  目标文件名  源文件名 (3)多线程编程方法参见附件。) 3. 调试报告: 1) 调试记录 2) 自我评析和总结 上机时间安排: 19周一 ~ 五 下午14:00 - 18:00 (6月27日开始) 指导教师签名: 年 月 日 系主任(或责任教师)签名: 年 月 日 五、源代码 #include #include #include "fstream.h" int readcount=0; //读者数目 int writecount=0; //写者数目 CRITICAL_SECTION RP_Write; //临界区 CRITICAL_SECTION cs_Write; CRITICAL_SECTION cs_Read; struct ThreadInfo //线程信息 { int Threadhao; //线程序号 char ThreadClass; //线程类别 double ThreadStartTime; //线程开始时间 double ThreadRunTime; //线程读写持续时间 }; void ReaderFun(char* file);//读者优先函数 void R_ReaderThread(void *p);//处理读者优先读者线程 void R_WriterThread(void *p);//处理读者优先写者线程 void WriterFun(char* file); void W_ReaderThread(void *p); void W_WriterThread(void *p); int main()//主函数 { char select; while (true) { cout<<"***************本程序实现读者-写者问题*******\n"<<endl; cout<<" 1:读者优先"<<endl; cout<<" 2:写者优先"<<endl; cout<<" 3:退出"<<endl; cout<<"\n*********************************************"<<endl; cout<<"请选择要进行的操作:"<>select; if(select!='1' && select!='2' && select!='3') cout<<"你操作有误,请重试!"<<endl; }while (select!='1' && select!='2' && select!='3'); system("cls"); if (select=='3') return 0;//退出 else if (select=='1')//调用读者优先 ReaderFun("peizhi.txt"); else if(select=='2')//调用写者优先 WriterFun("peizhi.txt"); cout<<"\n是否还有继续? 1. 继续 2.退出"<>select; if(select!='1' && select!='2' ) cout<<"你操作有误,请重试!"<<endl; }while (select!='1' && select!='2'); if(select=='2') return 0;// 退出 system("cls"); } return 0; }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值